forked from teamnwah/openmw-tes3coop
- very early version of the terrain engine, WORKING!
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@125 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
367b9754b2
commit
393d284a8a
7 changed files with 297 additions and 139 deletions
|
@ -144,14 +144,6 @@ struct MeshInfo
|
||||||
float *vbuf = vdest.ptr;
|
float *vbuf = vdest.ptr;
|
||||||
assert(vdest.length == vertRows*vertCols*8);
|
assert(vdest.length == vertRows*vertCols*8);
|
||||||
|
|
||||||
// Calculate the factor to multiply each height value with. The
|
|
||||||
// heights are very limited in range as they are stored in a
|
|
||||||
// single byte. Normal MW data uses a factor of 8, but we have to
|
|
||||||
// double this for each successive level since we're splicing
|
|
||||||
// several vertices together and need to allow larger differences
|
|
||||||
// for each vertex. The formula is 8*2^(level-1).
|
|
||||||
float scale = 4.0 * (1<<getLevel());
|
|
||||||
|
|
||||||
// Merge the two data sets together into the output buffer.
|
// Merge the two data sets together into the output buffer.
|
||||||
float offset = heightOffset;
|
float offset = heightOffset;
|
||||||
for(int y=0; y<vertRows; y++)
|
for(int y=0; y<vertRows; y++)
|
||||||
|
@ -160,21 +152,21 @@ struct MeshInfo
|
||||||
// height value. All the values in a row gives the height
|
// height value. All the values in a row gives the height
|
||||||
// relative to the previous value, and the first value in each
|
// relative to the previous value, and the first value in each
|
||||||
// row is relative to the first value in the previous row.
|
// row is relative to the first value in the previous row.
|
||||||
offset += *hmap;
|
offset += *cast(short*)hmap;
|
||||||
|
|
||||||
// This is the 'sliding offset' for this row. It's adjusted
|
// This is the 'sliding offset' for this row. It's adjusted
|
||||||
// for each vertex that's added, but only affects this row.
|
// for each vertex that's added, but only affects this row.
|
||||||
float rowofs = offset;
|
float rowofs = offset;
|
||||||
for(int x=0; x<vertCols; x++)
|
for(int x=0; x<vertCols; x++)
|
||||||
{
|
{
|
||||||
hmap++; // Skip the byte we just read
|
hmap+=2; // Skip the height we just read
|
||||||
|
|
||||||
// X and Y from the pregenerated buffer
|
// X and Y from the pregenerated buffer
|
||||||
*vbuf++ = *gmap++;
|
*vbuf++ = *gmap++;
|
||||||
*vbuf++ = *gmap++;
|
*vbuf++ = *gmap++;
|
||||||
|
|
||||||
// The height is calculated from the current offset
|
// The height is calculated from the current offset
|
||||||
*vbuf++ = rowofs * scale;
|
*vbuf++ = rowofs * 8;
|
||||||
|
|
||||||
// Normal vector.
|
// Normal vector.
|
||||||
*vbuf++ = *hmap++;
|
*vbuf++ = *hmap++;
|
||||||
|
@ -185,10 +177,9 @@ struct MeshInfo
|
||||||
*vbuf++ = *gmap++;
|
*vbuf++ = *gmap++;
|
||||||
*vbuf++ = *gmap++;
|
*vbuf++ = *gmap++;
|
||||||
|
|
||||||
// Adjust the offset for the next vertex. On the last
|
// Adjust the offset for the next vertex.
|
||||||
// iteration this will read past the current row, but
|
if(x < vertCols-1)
|
||||||
// that's OK since rowofs is discarded afterwards.
|
rowofs += *cast(short*)hmap;
|
||||||
rowofs += *hmap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,9 +334,20 @@ struct TerrainArchive
|
||||||
ifile.readArray(indexBufData);
|
ifile.readArray(indexBufData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasQuad(int X, int Y, int level)
|
||||||
|
{
|
||||||
|
if((level in quadMap) is null ||
|
||||||
|
(X in quadMap[level]) is null ||
|
||||||
|
(Y in quadMap[level][X]) is null)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Get info about a given quad from the index.
|
// Get info about a given quad from the index.
|
||||||
QuadInfo *getQuad(int X, int Y, int level)
|
QuadInfo *getQuad(int X, int Y, int level)
|
||||||
{
|
{
|
||||||
|
assert(hasQuad(X,Y,level), format("Cannot find quad %s %s level %s",
|
||||||
|
X, Y, level));
|
||||||
int ind = quadMap[level][X][Y];
|
int ind = quadMap[level][X][Y];
|
||||||
QuadInfo *res = &quadList[ind];
|
QuadInfo *res = &quadList[ind];
|
||||||
assert(res);
|
assert(res);
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
float h = (p.y + 2048)*2.0/CELL_WIDTH;
|
float h = (p.y + 2048)*2.0/CELL_WIDTH;
|
||||||
h *= h;
|
h *= h;
|
||||||
|
|
||||||
mNode->setPosition(p.x, -p.z, -32 - h);
|
mNode->setPosition(p.x, -p.z, -32 -h);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -55,16 +55,18 @@ private:
|
||||||
|
|
||||||
vd = mMeshDistance;
|
vd = mMeshDistance;
|
||||||
|
|
||||||
mObject->position(-vd,vd,-2048);
|
const int HEIGHT = -2048 - 10;
|
||||||
|
|
||||||
|
mObject->position(-vd,vd,HEIGHT);
|
||||||
mObject->textureCoord(0, 1);
|
mObject->textureCoord(0, 1);
|
||||||
|
|
||||||
mObject->position(-vd,-vd,-2048);
|
mObject->position(-vd,-vd,HEIGHT);
|
||||||
mObject->textureCoord(0, 0);
|
mObject->textureCoord(0, 0);
|
||||||
|
|
||||||
mObject->position(vd,-vd,-2048);
|
mObject->position(vd,-vd,HEIGHT);
|
||||||
mObject->textureCoord(1, 0);
|
mObject->textureCoord(1, 0);
|
||||||
|
|
||||||
mObject->position(vd,vd,-2048);
|
mObject->position(vd,vd,HEIGHT);
|
||||||
mObject->textureCoord(1, 1);
|
mObject->textureCoord(1, 1);
|
||||||
|
|
||||||
mObject->quad(0,1,2,3);
|
mObject->quad(0,1,2,3);
|
||||||
|
|
|
@ -84,14 +84,26 @@ public:
|
||||||
// Finally, create the material
|
// Finally, create the material
|
||||||
const std::string texName = info.getTexName();
|
const std::string texName = info.getTexName();
|
||||||
|
|
||||||
// Create or retrieve the material
|
// Set up the scene node.
|
||||||
mMaterial = MaterialManager::getSingleton().createOrRetrieve
|
mNode = parent->createChildSceneNode();
|
||||||
(texName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME).first;
|
mNode->attachObject(this);
|
||||||
|
|
||||||
|
// Finally, create or retrieve the material
|
||||||
|
if(MaterialManager::getSingleton().resourceExists(texName))
|
||||||
|
{
|
||||||
|
mMaterial = MaterialManager::getSingleton().getByName
|
||||||
|
(texName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No existing material. Create a new one.
|
||||||
|
mMaterial = MaterialManager::getSingleton().create
|
||||||
|
(texName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||||
|
|
||||||
Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
||||||
pass->setLightingEnabled(false);
|
pass->setLightingEnabled(false);
|
||||||
|
|
||||||
if(level != 1)
|
if(level > 1)
|
||||||
{
|
{
|
||||||
// This material just has a normal texture
|
// This material just has a normal texture
|
||||||
pass->createTextureUnitState(texName)
|
pass->createTextureUnitState(texName)
|
||||||
|
@ -100,6 +112,8 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
assert(level == 1);
|
||||||
|
|
||||||
// Get the background texture. TODO: We should get this from
|
// Get the background texture. TODO: We should get this from
|
||||||
// somewhere, no file names should be hard coded. The texture
|
// somewhere, no file names should be hard coded. The texture
|
||||||
// might exist as a .tga in earlier versions of the game, and
|
// might exist as a .tga in earlier versions of the game, and
|
||||||
|
@ -173,10 +187,6 @@ public:
|
||||||
tus->setTextureScale(scale, scale);
|
tus->setTextureScale(scale, scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, set up the scene node.
|
|
||||||
mNode = parent->createChildSceneNode();
|
|
||||||
mNode->attachObject(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~TerrainMesh()
|
~TerrainMesh()
|
||||||
|
|
|
@ -275,7 +275,7 @@ extern "C"
|
||||||
addResourceLocation("cache/terrain/", "FileSystem", "General");
|
addResourceLocation("cache/terrain/", "FileSystem", "General");
|
||||||
|
|
||||||
// Enter superman mode
|
// Enter superman mode
|
||||||
mCamera->setFarClipDistance(32*CELL_WIDTH);
|
mCamera->setFarClipDistance(40*CELL_WIDTH);
|
||||||
//ogre_setFog(0.7, 0.7, 0.7, 200, 32*CELL_WIDTH);
|
//ogre_setFog(0.7, 0.7, 0.7, 200, 32*CELL_WIDTH);
|
||||||
d_terr_superman();
|
d_terr_superman();
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ module terrain.generator;
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.string;
|
import std.string;
|
||||||
|
import std.math2;
|
||||||
import std.c.string;
|
import std.c.string;
|
||||||
|
|
||||||
import terrain.cachewriter;
|
import terrain.cachewriter;
|
||||||
|
@ -80,7 +80,7 @@ void generate(char[] filename)
|
||||||
texSizes[5] = 512;
|
texSizes[5] = 512;
|
||||||
texSizes[4] = 256;
|
texSizes[4] = 256;
|
||||||
texSizes[3] = 256;
|
texSizes[3] = 256;
|
||||||
texSizes[2] = 256;
|
texSizes[2] = 512;
|
||||||
texSizes[1] = 64;
|
texSizes[1] = 64;
|
||||||
|
|
||||||
// Set some general parameters for the runtime
|
// Set some general parameters for the runtime
|
||||||
|
@ -144,6 +144,20 @@ struct GenLevelResult
|
||||||
quad.meshes[0].alphas[i].buffer = data[i*s..(i+1)*s];
|
quad.meshes[0].alphas[i].buffer = data[i*s..(i+1)*s];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the height offset
|
||||||
|
float getHeight()
|
||||||
|
{
|
||||||
|
if(hasMesh)
|
||||||
|
{
|
||||||
|
assert(quad.meshes.length == 1);
|
||||||
|
return quad.meshes[0].info.heightOffset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// The default mesh starts at 2048 = 256*8 units below water
|
||||||
|
// level.
|
||||||
|
return -256;
|
||||||
|
}
|
||||||
|
|
||||||
bool isEmpty()
|
bool isEmpty()
|
||||||
{
|
{
|
||||||
return (data.length == 0) && !hasMesh;
|
return (data.length == 0) && !hasMesh;
|
||||||
|
@ -265,10 +279,8 @@ struct GenLevelResult
|
||||||
|
|
||||||
mi.vertRows = size;
|
mi.vertRows = size;
|
||||||
mi.vertCols = size;
|
mi.vertCols = size;
|
||||||
// 1 height + 3 normal components = 4 bytes per vertex. The reader
|
// 2 height bytes + 3 normal components = 5 bytes per vertex.
|
||||||
// algorithm (fillVertexBuffer) needs 1 extra byte so add that
|
mh.vertexBuffer = new byte[5*size*size];
|
||||||
// too.
|
|
||||||
mh.vertexBuffer = new byte[4*size*size+1];
|
|
||||||
|
|
||||||
hasMesh = true;
|
hasMesh = true;
|
||||||
}
|
}
|
||||||
|
@ -304,20 +316,7 @@ void genIndexData()
|
||||||
{
|
{
|
||||||
scope auto _trc = new MTrace("genIndexData");
|
scope auto _trc = new MTrace("genIndexData");
|
||||||
|
|
||||||
// Generate mesh data for each level.
|
// FIXME: Do this at runtime.
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: The mesh data is very easy to generate, and we haven't
|
|
||||||
really tested whether it's worth it to pregenerate it rather than
|
|
||||||
to just calculate it at runtime. Unlike the index buffer below
|
|
||||||
(which is just a memcpy at runtime, and definitely worth
|
|
||||||
pregenerating), we have to loop through all the vertices at
|
|
||||||
runtime anyway in order to splice this with the height data. It's
|
|
||||||
possible that the additional memory use, pluss the slowdown
|
|
||||||
(CPU-cache-wise) of reading from two buffers instead of one, makes
|
|
||||||
it worthwhile to generate this data at runtime instead. However I
|
|
||||||
guess the differences will be very small either way.
|
|
||||||
*/
|
|
||||||
for(int lev=1; lev<=6; lev++)
|
for(int lev=1; lev<=6; lev++)
|
||||||
{
|
{
|
||||||
// Make a new buffer to store the data
|
// Make a new buffer to store the data
|
||||||
|
@ -353,7 +352,7 @@ void genIndexData()
|
||||||
cache.addVertexBuffer(lev,vertList);
|
cache.addVertexBuffer(lev,vertList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next up, triangle indices
|
// Pregenerate triangle indices
|
||||||
int size = 64*64*6;
|
int size = 64*64*6;
|
||||||
auto indList = new ushort[size];
|
auto indList = new ushort[size];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
@ -531,8 +530,9 @@ void genLevel1Meshes(ref GenLevelResult res)
|
||||||
// The vertex data from the ESM
|
// The vertex data from the ESM
|
||||||
byte data = heightData[offs];
|
byte data = heightData[offs];
|
||||||
|
|
||||||
// Write the height byte
|
// Write the height value as a short (2 bytes)
|
||||||
verts[index++] = data;
|
*(cast(short*)&verts[index]) = data;
|
||||||
|
index+=2;
|
||||||
|
|
||||||
// Calculate the height here, even though we don't store
|
// Calculate the height here, even though we don't store
|
||||||
// it. We use it to find the min and max values.
|
// it. We use it to find the min and max values.
|
||||||
|
@ -557,7 +557,7 @@ void genLevel1Meshes(ref GenLevelResult res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we wrote exactly the right amount of data
|
// Make sure we wrote exactly the right amount of data
|
||||||
assert(index == verts.length-1);
|
assert(index == verts.length);
|
||||||
|
|
||||||
// Store the min/max values
|
// Store the min/max values
|
||||||
mi.minHeight = min * 8;
|
mi.minHeight = min * 8;
|
||||||
|
@ -864,111 +864,160 @@ void mergeMesh(GenLevelResult[] sub, ref GenLevelResult res)
|
||||||
// level above the cell level.
|
// level above the cell level.
|
||||||
int shift = res.quad.info.level - 1;
|
int shift = res.quad.info.level - 1;
|
||||||
assert(shift >= 1);
|
assert(shift >= 1);
|
||||||
|
assert(sub.length == 4);
|
||||||
// Constants
|
|
||||||
int intervals = 64;
|
|
||||||
int vertNum = intervals+1;
|
|
||||||
int vertSep = 128 << shift;
|
|
||||||
|
|
||||||
// Allocate the result buffer
|
// Allocate the result buffer
|
||||||
res.allocMesh(vertNum);
|
res.allocMesh(65);
|
||||||
|
|
||||||
MeshHolder *mh = &res.quad.meshes[0];
|
MeshHolder *mh = &res.quad.meshes[0];
|
||||||
MeshInfo *mi = &mh.info;
|
MeshInfo *mi = &mh.info;
|
||||||
|
|
||||||
// Basic info
|
// Basic info
|
||||||
mi.worldWidth = vertSep*intervals;
|
mi.worldWidth = 8192 << shift;
|
||||||
assert(mi.worldWidth == 8192<<shift);
|
|
||||||
|
|
||||||
// Get the height from the first cell
|
// Copy the mesh height from the top left mesh
|
||||||
float rowheight;
|
mi.heightOffset = sub[0].getHeight();
|
||||||
if(sub[0].isEmpty())
|
|
||||||
rowheight = 0.0;
|
|
||||||
else
|
|
||||||
rowheight = sub[0].quad.meshes[0].info.heightOffset;
|
|
||||||
|
|
||||||
// This is also the offset for the entire mesh
|
// Output buffer
|
||||||
mi.heightOffset = rowheight;
|
byte verts[] = mh.vertexBuffer;
|
||||||
|
|
||||||
// Just set bogus data for now
|
// Bytes per vertex
|
||||||
int[] tmp = cast(int[])mh.vertexBuffer[0..$-1];
|
const int VSIZE = 5;
|
||||||
tmp[] = 0x7f000000;
|
|
||||||
float scale = 8.0 * (1<<shift);
|
|
||||||
mi.minHeight = mi.maxHeight = mi.heightOffset * scale;
|
|
||||||
return;
|
|
||||||
|
|
||||||
byte *vertPtr = mh.vertexBuffer.ptr;
|
// Used to calculate the max and min heights
|
||||||
|
float minh = 300000.0;
|
||||||
|
float maxh = -300000.0;
|
||||||
|
|
||||||
// First off, rewrite this to use indices instead of pointers. It's
|
foreach(si, s; sub)
|
||||||
// much safer and clearer.
|
|
||||||
|
|
||||||
// Loop through each 'row' of submeshes
|
|
||||||
for(int subY=0; subY<2; subY++)
|
|
||||||
{
|
{
|
||||||
// Loop through each row of vertices
|
int SX = si % 2;
|
||||||
for(int row=0; row<65; row++)
|
int SY = si / 2;
|
||||||
|
|
||||||
|
// Find the offset in the destination buffer
|
||||||
|
int dest = SX*32 + SY*65*32;
|
||||||
|
dest *= VSIZE;
|
||||||
|
|
||||||
|
void putValue(int val)
|
||||||
{
|
{
|
||||||
// FIXME: Ok, we have to skip each other row as well, of course.
|
assert(val >= short.min && val <= short.max);
|
||||||
|
*(cast(short*)&verts[dest]) = val;
|
||||||
|
dest += 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Loop through both sub meshes, left and right
|
if(s.hasMesh)
|
||||||
for(int subX=0; subX<2; subX++)
|
{
|
||||||
|
auto m = &s.quad.meshes[0];
|
||||||
|
auto i = &m.info;
|
||||||
|
|
||||||
|
minh = min(minh, i.minHeight);
|
||||||
|
maxh = max(maxh, i.maxHeight);
|
||||||
|
|
||||||
|
byte[] source = m.vertexBuffer;
|
||||||
|
int src = 0;
|
||||||
|
|
||||||
|
int getValue()
|
||||||
{
|
{
|
||||||
GenLevelResult *s = &sub[subX+2*subY];
|
int s = *(cast(short*)&source[src]);
|
||||||
|
src += 2;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have any data
|
// Loop through all the vertices in the mesh
|
||||||
if(!s.isEmpty() && 0)
|
for(int y=0;y<33;y++)
|
||||||
|
{
|
||||||
|
// Skip the first row in the mesh if there was a mesh
|
||||||
|
// above us. We assume that the previously written row
|
||||||
|
// already has the correct information.
|
||||||
|
if(y==0 && SY != 0)
|
||||||
{
|
{
|
||||||
MeshHolder *smh = &s.quad.meshes[0];
|
src += 65*VSIZE;
|
||||||
byte* inPtr = smh.vertexBuffer.ptr;
|
dest += 65*VSIZE;
|
||||||
|
continue;
|
||||||
// Loop through each vertex in this mesh. We skip two
|
|
||||||
// at a time.
|
|
||||||
for(int v=0; v<64; v+=2)
|
|
||||||
{
|
|
||||||
// Handle the v=0 case
|
|
||||||
|
|
||||||
// Count the height from the two next vertices
|
|
||||||
int data = *inPtr++;
|
|
||||||
inPtr++;inPtr++;inPtr++; // Skip the first normal
|
|
||||||
data += *inPtr++;
|
|
||||||
|
|
||||||
// Divide by two, since the result needs to fit in
|
|
||||||
// one byte. We compensate for this when we regen
|
|
||||||
// the mesh at runtime.
|
|
||||||
data >>= 1;
|
|
||||||
assert(data < 128 && data >= -128);
|
|
||||||
|
|
||||||
*vertPtr++ = data;
|
|
||||||
|
|
||||||
// Copy over the normal
|
|
||||||
*vertPtr++ = *inPtr++;
|
|
||||||
*vertPtr++ = *inPtr++;
|
|
||||||
*vertPtr++ = *inPtr++;
|
|
||||||
}
|
|
||||||
// Store the last one here. It _should_ be the
|
|
||||||
// same as the first in the next section, if
|
|
||||||
// present.
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Handle the first vertex of the row outside the
|
||||||
|
// loop.
|
||||||
|
int height = getValue();
|
||||||
|
|
||||||
|
// If this isn't the very first row, sum up two row
|
||||||
|
// heights and skip the first row.
|
||||||
|
if(y!=0)
|
||||||
{
|
{
|
||||||
// No data in this mesh. Just write zeros.
|
// Skip the rest of the row.
|
||||||
for(int v=0; v<32; v++)
|
src += 64*VSIZE + 3;
|
||||||
{
|
|
||||||
// Height
|
|
||||||
*vertPtr++ = 0;
|
|
||||||
|
|
||||||
// Normal, pointing straight upwards
|
// Add the second height
|
||||||
*vertPtr++ = 0;
|
height += getValue();
|
||||||
*vertPtr++ = 0;
|
|
||||||
*vertPtr++ = 0x7f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
putValue(height);
|
||||||
|
|
||||||
|
// Copy the normal
|
||||||
|
verts[dest++] = source[src++];
|
||||||
|
verts[dest++] = source[src++];
|
||||||
|
verts[dest++] = source[src++];
|
||||||
|
|
||||||
|
// Loop through the remaining 64 vertices in this row,
|
||||||
|
// processing two at a time.
|
||||||
|
for(int x=0;x<32;x++)
|
||||||
|
{
|
||||||
|
height = getValue();
|
||||||
|
|
||||||
|
// Sum up the next two heights
|
||||||
|
src += 3; // Skip normal
|
||||||
|
height += getValue();
|
||||||
|
|
||||||
|
// Set the height
|
||||||
|
putValue(height);
|
||||||
|
|
||||||
|
// Copy the normal
|
||||||
|
verts[dest++] = source[src++];
|
||||||
|
verts[dest++] = source[src++];
|
||||||
|
verts[dest++] = source[src++];
|
||||||
|
}
|
||||||
|
// Skip to the next row
|
||||||
|
dest += 32*VSIZE;
|
||||||
|
}
|
||||||
|
assert(src == source.length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minh = min(minh, -2048);
|
||||||
|
maxh = max(maxh, -2048);
|
||||||
|
|
||||||
|
// Set all the vertices to zero.
|
||||||
|
for(int y=0;y<33;y++)
|
||||||
|
{
|
||||||
|
if(y==0 && SY != 0)
|
||||||
|
{
|
||||||
|
dest += 65*VSIZE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x=0;x<33;x++)
|
||||||
|
{
|
||||||
|
if(x==0 && SX != 0)
|
||||||
|
{
|
||||||
|
dest += VSIZE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero height and vertical normal
|
||||||
|
verts[dest++] = 0;
|
||||||
|
verts[dest++] = 0;
|
||||||
|
verts[dest++] = 0;
|
||||||
|
verts[dest++] = 0;
|
||||||
|
verts[dest++] = 0x7f;
|
||||||
|
}
|
||||||
|
// Skip to the next row
|
||||||
|
dest += 32*VSIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(vertPtr == mh.vertexBuffer.ptr + mh.vertexBuffer.length - 1);
|
|
||||||
|
|
||||||
// Set max and min values here
|
mi.minHeight = minh;
|
||||||
|
mi.maxHeight = maxh;
|
||||||
|
assert(minh <= maxh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------- OLD CODE - use these snippets later -------
|
// ------- OLD CODE - use these snippets later -------
|
||||||
|
|
69
terrain/myfile.d
Normal file
69
terrain/myfile.d
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||||
|
Copyright (C) 2009 Nicolay Korslund
|
||||||
|
WWW: http://openmw.sourceforge.net/
|
||||||
|
|
||||||
|
This file (archive.d) is part of the OpenMW package.
|
||||||
|
|
||||||
|
OpenMW is distributed as free software: you can redistribute it
|
||||||
|
and/or modify it under the terms of the GNU General Public License
|
||||||
|
version 3, as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
version 3 along with this program. If not, see
|
||||||
|
http://www.gnu.org/licenses/ .
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
import std.stream;
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
// Add a couple of helper functions to the file stream
|
||||||
|
class MyFile : File
|
||||||
|
{
|
||||||
|
this(string filename, FileMode mode = FileMode.In)
|
||||||
|
{
|
||||||
|
super(filename, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill(T)(ref T t)
|
||||||
|
{
|
||||||
|
readExact(&t, T.sizeof);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(T)(ref T t)
|
||||||
|
{
|
||||||
|
writeExact(&t, T.sizeof);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillArray(T)(T[] t)
|
||||||
|
{
|
||||||
|
readExact(t.ptr, t.length*T.sizeof);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpArray(T)(T[] t)
|
||||||
|
{
|
||||||
|
writeExact(t.ptr, t.length*T.sizeof);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readArray(T)(ref T[] arr)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
read(size);
|
||||||
|
assert(size < 1024*1024 && size > 0);
|
||||||
|
arr = new T[size];
|
||||||
|
fillArray!(T)(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeArray(T)(T[] t)
|
||||||
|
{
|
||||||
|
int size = t.length;
|
||||||
|
write(size);
|
||||||
|
dumpArray!(T)(t);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,8 @@ import std.file, std.stdio;
|
||||||
|
|
||||||
char[] cacheDir = "cache/terrain/";
|
char[] cacheDir = "cache/terrain/";
|
||||||
|
|
||||||
// Enable this to render one single terrain mesh
|
// Enable this to render single terrain meshes instead of the entire
|
||||||
|
// data set
|
||||||
//debug=singleMesh;
|
//debug=singleMesh;
|
||||||
|
|
||||||
void initTerrain(bool doGen)
|
void initTerrain(bool doGen)
|
||||||
|
@ -55,12 +56,37 @@ void initTerrain(bool doGen)
|
||||||
|
|
||||||
debug(singleMesh)
|
debug(singleMesh)
|
||||||
{
|
{
|
||||||
// Used for debugging single terrain meshes
|
int X = 22;
|
||||||
auto node = terr_createChildNode(20000,-60000,null);
|
int Y = 0;
|
||||||
auto info = g_archive.getQuad(0,0,1);
|
bool next = false;
|
||||||
g_archive.mapQuad(info);
|
|
||||||
auto mi = g_archive.getMeshInfo(0);
|
void doQuad(int x, int y, int lev)
|
||||||
auto m = terr_makeMesh(node, mi, info.level, TEX_SCALE);
|
{
|
||||||
|
if(!g_archive.hasQuad(x,y,lev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int diffx = x-X;
|
||||||
|
int diffy = y-Y;
|
||||||
|
|
||||||
|
diffx *= 8192;
|
||||||
|
diffy *= 8192;
|
||||||
|
|
||||||
|
if(diffx == 0 && lev == 2)
|
||||||
|
diffx = 8192 * 2;
|
||||||
|
|
||||||
|
auto node = terr_createChildNode(20000+diffx,-60000+diffy,null);
|
||||||
|
auto info = g_archive.getQuad(x,y,lev);
|
||||||
|
g_archive.mapQuad(info);
|
||||||
|
auto mi = g_archive.getMeshInfo(0);
|
||||||
|
terr_makeMesh(node, mi, info.level, TEX_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
|
doQuad(X,Y,1);
|
||||||
|
doQuad(X+1,Y,1);
|
||||||
|
doQuad(X,Y+1,1);
|
||||||
|
doQuad(X+1,Y+1,1);
|
||||||
|
|
||||||
|
doQuad(X + (next?2:0),Y,2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue