From f739bf90f18de50682ca98e570ab5cdd53d7caa9 Mon Sep 17 00:00:00 2001 From: nkorslund Date: Mon, 8 Jun 2009 12:59:00 +0000 Subject: [PATCH] Terrain code 90% done. git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@123 ea6a568a-9f4f-0410-981a-c910a81bb256 --- input/events.d | 6 +- ogre/cpp_interface.cpp | 12 +-- ogre/cpp_ogre.cpp | 2 +- ogre/ogre.d | 4 - terrain/archive.d | 60 ++++++------ terrain/bindings.d | 5 +- terrain/cpp_baseland.cpp | 74 +++++--------- terrain/cpp_mesh.cpp | 45 ++++----- terrain/cpp_terrain.cpp | 207 ++++++++++++++++++++++++++++++++------- terrain/generator.d | 24 +++-- terrain/quad.d | 46 ++------- terrain/terrain.d | 33 ++++++- 12 files changed, 312 insertions(+), 206 deletions(-) diff --git a/input/events.d b/input/events.d index 896481c7f..135dd5b48 100644 --- a/input/events.d +++ b/input/events.d @@ -259,9 +259,9 @@ bool isPressed(Keys key) return false; } -// Enable superman mode, ie. flight and super-speed. This is getting -// very spaghetti-ish. -extern(C) void d_superman() +// Enable superman mode, ie. flight and super-speed. Only used for +// debugging the terrain mode. +extern(C) void d_terr_superman() { bullet_fly(); speed = 8000; diff --git a/ogre/cpp_interface.cpp b/ogre/cpp_interface.cpp index 3374f6066..5805b8736 100644 --- a/ogre/cpp_interface.cpp +++ b/ogre/cpp_interface.cpp @@ -204,8 +204,8 @@ extern "C" void ogre_makeScene() // Morrowind uses, and it automagically makes everything work as it // should. SceneNode *rt = mSceneMgr->getRootSceneNode(); - root = rt->createChildSceneNode(); - root->pitch(Degree(-90)); + mwRoot = rt->createChildSceneNode(); + mwRoot->pitch(Degree(-90)); /* g_light = mSceneMgr->createLight("carry"); @@ -397,7 +397,7 @@ extern "C" SceneNode *ogre_insertNode(SceneNode *base, char* name, float scale) { //std::cout << "ogre_insertNode(" << name << ")\n"; - SceneNode *node = root->createChildSceneNode(name); + SceneNode *node = mwRoot->createChildSceneNode(name); // Make a copy of the node cloneNode(base, node, name); @@ -453,7 +453,7 @@ extern "C" void ogre_createWater(float level) 150000,150000 ); Entity *ent = mSceneMgr->createEntity( "WaterEntity", "water" ); - root->createChildSceneNode()->attachObject(ent); + mwRoot->createChildSceneNode()->attachObject(ent); ent->setCastShadows(false); } @@ -699,8 +699,8 @@ extern "C" void ogre_createMaterial(char *name, // Name to give extern "C" SceneNode *ogre_getDetachedNode() { - SceneNode *node = root->createChildSceneNode(); - root->removeChild(node); + SceneNode *node = mwRoot->createChildSceneNode(); + mwRoot->removeChild(node); return node; } diff --git a/ogre/cpp_ogre.cpp b/ogre/cpp_ogre.cpp index c70c7d5a6..a2ae56c28 100644 --- a/ogre/cpp_ogre.cpp +++ b/ogre/cpp_ogre.cpp @@ -71,7 +71,7 @@ int32_t guiMode = 0; // Root node for all objects added to the scene. This is rotated so // that the OGRE coordinate system matches that used internally in // Morrowind. -SceneNode *root; +SceneNode *mwRoot; // Include the other parts of the code, and make one big happy object // file. This is extremely against the grain of C++ "recomended diff --git a/ogre/ogre.d b/ogre/ogre.d index 79fae93d5..05523dfcc 100644 --- a/ogre/ogre.d +++ b/ogre/ogre.d @@ -132,10 +132,6 @@ void setupOgre(bool debugOut) OgreException("Configuration abort"); ogre_initWindow(); - - // We set up the scene manager in a separate function, since we - // might have to do that for every new cell later on, and handle - // exterior cells differently, etc. ogre_makeScene(); ogreSetup = true; diff --git a/terrain/archive.d b/terrain/archive.d index ad2cd5ea0..4c5037761 100644 --- a/terrain/archive.d +++ b/terrain/archive.d @@ -32,6 +32,28 @@ version(Windows) else static int pageSize = 4*1024; +extern(C) +{ + // Convert a texture index to string + char *d_terr_getTexName(int index) + { return g_archive.getString(index).ptr; } + + // Fill various hardware buffers from cache + void d_terr_fillVertexBuffer(MeshInfo *mi, float *buffer) + { mi.fillVertexBuffer(buffer); } + + void d_terr_fillIndexBuffer(MeshInfo *mi, ushort *buffer) + { mi.fillIndexBuffer(buffer); } + + void d_terr_fillAlphaBuffer(AlphaInfo *mi, ubyte *buffer) + { mi.fillAlphaBuffer(buffer); } + + // Get a given alpha map struct belonging to a mesh + AlphaInfo *d_terr_getAlphaInfo(MeshInfo *mi, int index) + { return mi.getAlphaInfo(index); } + +} + // Info about the entire quad. TODO: Some of this (such as the texture // scale and probably the width and radius) can be generated at // loadtime and is common for all quads on the same level. We could @@ -62,11 +84,11 @@ struct QuadInfo size_t offset, size; } - // Info about an alpha map belonging to a mesh struct AlphaInfo { - size_t bufSize, bufOffset; + // Position of the actual image data + ulong bufSize, bufOffset; // The texture name for this layer. The actual string is stored in // the archive's string buffer. @@ -78,21 +100,11 @@ struct AlphaInfo { g_archive.copy(abuf, bufOffset, bufSize); } - - // Get the texture for this alpha layer - char[] getTexName() - { - return g_archive.getString(texName); - } - - // Get the material name to give the alpha texture - char[] getAlphaName() - { - return g_archive.getString(alphaName); - } } +static assert(AlphaInfo.sizeof == 6*4); // Info about each submesh +align(1) struct MeshInfo { // Bounding box info @@ -110,11 +122,11 @@ struct MeshInfo float heightOffset; // Size and offset of the vertex buffer - size_t vertBufSize, vertBufOffset; + ulong vertBufSize, vertBufOffset; // Number and offset of AlphaInfo blocks int alphaNum; - size_t alphaOffset; + ulong alphaOffset; // Texture name. Index to the string table. int texName; @@ -208,21 +220,9 @@ struct MeshInfo res += num; return res; } - - // Get the size of the alpha textures (in pixels). - int getAlphaSize() - { return g_archive.alphaSize; } - - // Get the texture and material name to use for this mesh. - char[] getTexName() - { return g_archive.getString(texName); } - - float getTexScale() - { return g_archive.curQuad.texScale; } - - char[] getBackgroundTex() - { return "_land_default.dds"; } } +static assert(MeshInfo.sizeof == 17*4); + struct ArchiveHeader { diff --git a/terrain/bindings.d b/terrain/bindings.d index 4da9aef8d..090cc51d5 100644 --- a/terrain/bindings.d +++ b/terrain/bindings.d @@ -8,9 +8,10 @@ extern(C): SceneNode terr_createChildNode(float relX, float relY, SceneNode); void terr_destroyNode(SceneNode); -Bounds terr_makeBounds(float minHeight, float maxHeight, float width); +Bounds terr_makeBounds(float minHeight, float maxHeight, float width, SceneNode); +void terr_killBounds(Bounds); float terr_getSqCamDist(Bounds); -MeshObj terr_makeMesh(int segment, SceneNode); +MeshObj terr_makeMesh(SceneNode,void*,int,float); void terr_killMesh(MeshObj); void terr_genData(); diff --git a/terrain/cpp_baseland.cpp b/terrain/cpp_baseland.cpp index 6ad1dcb9b..2607476bc 100644 --- a/terrain/cpp_baseland.cpp +++ b/terrain/cpp_baseland.cpp @@ -1,16 +1,13 @@ class BaseLand { public: - BaseLand(Ogre::SceneNode* s) - : mTerrainSceneNode(s) + BaseLand() { - createMaterial(); createMesh(); } ~BaseLand() { - destroyMaterial(); destroyMesh(); } @@ -21,9 +18,7 @@ public: // Recreate the mesh if the view distance has increased if ( vd > mMeshDistance ) { - destroyMaterial(); destroyMesh(); - createMaterial(); createMesh(); } @@ -31,41 +26,52 @@ public: p.x -= ((int)p.x % CELL_WIDTH); p.z -= ((int)p.z % CELL_WIDTH); - float h = p.y + 2048; - h = pow(h/CELL_WIDTH*2,2); - if ( h < 0 ) h = 0; + float h = (p.y + 2048)*2.0/CELL_WIDTH; + h *= h; - mNode->setPosition(p.x, -32 - h, p.z); + mNode->setPosition(p.x, -p.z, -32 - h); } private: void createMesh() { + float vd = mCamera->getFarClipDistance(); + + mMeshDistance = vd; + + vd = vd/CELL_WIDTH * 32; + + mMat = Ogre::MaterialManager::getSingleton(). + create("BaseLandMat", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + Ogre::TextureUnitState* us = mMat->getTechnique(0)->getPass(0)->createTextureUnitState("_land_default.dds"); + us->setTextureScale(1.0f/vd,1.0f/vd); + + mMat->getTechnique(0)->getPass(0)->setDepthBias(-1); + mObject = mSceneMgr->createManualObject("BaseLand"); mObject->begin("BaseLandMat", Ogre::RenderOperation::OT_TRIANGLE_LIST); - Ogre::Real vd = mCamera->getFarClipDistance(); - vd += CELL_WIDTH - ((int)vd % CELL_WIDTH); - - mMeshDistance = vd; + vd = mMeshDistance; - mObject->position(-vd,-2048, vd); + mObject->position(-vd,vd,-2048); mObject->textureCoord(0, 1); - mObject->position(vd,-2048, vd); - mObject->textureCoord(1, 1); + mObject->position(-vd,-vd,-2048); + mObject->textureCoord(0, 0); - mObject->position(vd,-2048, -vd); + mObject->position(vd,-vd,-2048); mObject->textureCoord(1, 0); - mObject->position(-vd,-2048, -vd); - mObject->textureCoord(0, 0); + mObject->position(vd,vd,-2048); + mObject->textureCoord(1, 1); mObject->quad(0,1,2,3); mObject->end(); - mNode = mTerrainSceneNode->createChildSceneNode(); + mNode = g_rootTerrainNode->createChildSceneNode(); mNode->attachObject(mObject); } @@ -74,31 +80,7 @@ private: mNode->detachAllObjects(); mSceneMgr->destroyManualObject(mObject); mNode->getParentSceneNode()->removeAndDestroyChild(mNode->getName()); - } - - // FIXME: We destroy and recreate the material (and mesh) when the - // view distance changes. If we make a built-in auto-adjusting FPS - // optimizer, this will happen quite a lot, so it's worth trying to - // optimize this. This might be moot however when we implement - // water, since BaseLand may not be needed anymore. - void createMaterial() - { - float vd = mCamera->getFarClipDistance(); - vd += CELL_WIDTH - ((int)vd % CELL_WIDTH); - vd = vd/CELL_WIDTH * 2; - - mMat = Ogre::MaterialManager::getSingleton(). - create(std::string("BaseLandMat"), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - Ogre::TextureUnitState* us = mMat->getTechnique(0)->getPass(0)->createTextureUnitState("_land_default.dds"); - us->setTextureScale(0.1f/vd,0.1f/vd); - - mMat->getTechnique(0)->getPass(0)->setDepthBias(-1); - } - void destroyMaterial() - { mMat->getCreator()->remove(mMat->getHandle()); mMat = Ogre::MaterialPtr(); } @@ -114,6 +96,4 @@ private: ///In essence, the farViewDistance of the camera last frame Ogre::Real mMeshDistance; - - Ogre::SceneNode* mTerrainSceneNode; }; diff --git a/terrain/cpp_mesh.cpp b/terrain/cpp_mesh.cpp index 6c2b091fc..9e5d51f7f 100644 --- a/terrain/cpp_mesh.cpp +++ b/terrain/cpp_mesh.cpp @@ -3,18 +3,13 @@ class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject { public: - TerrainMesh(int segNum, Ogre::SceneNode *parent) + TerrainMesh(Ogre::SceneNode *parent, const MeshInfo &info, + int level, float scale) : Ogre::Renderable(), Ogre::MovableObject() { - using namespace Ogre; - - // Get the mesh properties from the archive. The pointer is only - // valid for the duration of this function. - const MeshInfo &info = *g_archive.getMeshInfo(segNum); - - // Split all this off into sub-functions again later when you're - // finished. + // This is a bit messy, with everything in one function. We could + // split it up later. // Use MW coordinates all the way mBounds.setExtents(0,0,info.minHeight, @@ -93,8 +88,7 @@ public: Pass* pass = mMaterial->getTechnique(0)->getPass(0); pass->setLightingEnabled(false); - int lev = info.getLevel(); - if(lev != 1) + if(level != 1) { // This material just has a normal texture pass->createTextureUnitState(texName) @@ -103,16 +97,17 @@ public: } else { - // We have to use alpha splatting - float scale = info.getTexScale(); - - // Get the background texture - const char *bgTex = info.getBackgroundTex(); + // Get the background texture. TODO: We should get this from + // somewhere, no file names should be hard coded. The texture + // might exist as a .tga in earlier versions of the game, and + // we might also want to specify a different background + // texture on some meshes. + //const char *bgTex = info.getBackgroundTex(); + + const char *bgTex = "_land_default.dds"; pass->createTextureUnitState(bgTex) ->setTextureScale(scale,scale); - int alphaSize = info.getAlphaSize(); - // Loop through all the textures in this mesh for(int tnum=0; tnumdetachAllObjects(); mNode->getCreator()->destroySceneNode(mNode); + + // TODO: This used to crash. See what happens now. + delete mVertices; + delete mIndices; } //----------------------------------------------------------------------- diff --git a/terrain/cpp_terrain.cpp b/terrain/cpp_terrain.cpp index a37c0f038..ef29419f2 100644 --- a/terrain/cpp_terrain.cpp +++ b/terrain/cpp_terrain.cpp @@ -22,76 +22,211 @@ const int CELL_WIDTH = 8192; +SceneNode *g_rootTerrainNode; +int g_alphaSize; + +struct MeshInfo; +struct AlphaInfo; + +// D functions +extern "C" +{ + void d_terr_superman(); + void d_terr_terrainUpdate(); + + char *d_terr_getTexName(int32_t); + + void d_terr_fillVertexBuffer(const MeshInfo*,float*); + void d_terr_fillIndexBuffer(const MeshInfo*,uint16_t*); + AlphaInfo *d_terr_getAlphaInfo(const MeshInfo*,int32_t); + + void d_terr_fillAlphaBuffer(const AlphaInfo*,uint8_t*); +} + +// Info about a submesh. This is a clone of the struct defined in +// archive.d. TODO: Make sure the D and C++ structs are of the same +// size and alignment. +struct MeshInfo +{ + // Bounding box info + float minHeight, maxHeight; + float worldWidth; + + // Vertex and index numbers + int32_t vertRows, vertCols; + int32_t indexCount; + + // Scene node position (relative to the parent node) + float x, y; + + // Height offset to apply to all vertices + float heightOffset; + + // Size and offset of the vertex buffer + int64_t vertBufSize, vertBufOffset; + + // Number and offset of AlphaInfo blocks + int32_t alphaNum; + uint64_t alphaOffset; + + // Texture name. Index to the string table. + int32_t texName; + + inline void fillVertexBuffer(float *buffer) const + { + d_terr_fillVertexBuffer(this, buffer); + } + + inline void fillIndexBuffer(uint16_t *buffer) const + { + d_terr_fillIndexBuffer(this, buffer); + } + + inline char* getTexName() const + { + return d_terr_getTexName(texName); + } + + inline AlphaInfo *getAlphaInfo(int tnum) const + { + return d_terr_getAlphaInfo(this, tnum); + } +}; + +// Info about an alpha map belonging to a mesh +struct AlphaInfo +{ + // Position of the actual image data + uint64_t bufSize, bufOffset; + + // The texture name for this layer. The actual string is stored in + // the archive's string buffer. + int32_t texName; + int32_t alphaName; + + inline char* getTexName() const + { + return d_terr_getTexName(texName); + } + + inline char* getAlphaName() const + { + return d_terr_getTexName(alphaName); + } + + inline void fillAlphaBuffer(uint8_t *buffer) const + { + return d_terr_fillAlphaBuffer(this, buffer); + } +}; + #include "cpp_baseland.cpp" -//#include "cpp_mesh.cpp" +#include "cpp_mesh.cpp" BaseLand *g_baseLand; -SceneNode *g_rootTerrainNode; class TerrainFrameListener : public FrameListener { protected: bool frameEnded(const FrameEvent& evt) { - //g_rootQuad->update(); + d_terr_terrainUpdate(); g_baseLand->update(); return true; } }; +// Functions called from D extern "C" { - void d_superman(); - - SceneNode* terr_createChildNode(float relX, float relY, + SceneNode* terr_createChildNode(float x, float y, SceneNode *parent) - {} + { + Ogre::Vector3 pos(x,y,0); + if(parent == NULL) + parent = g_rootTerrainNode; + + assert(parent); + return parent->createChildSceneNode(pos); + } void terr_destroyNode(SceneNode *node) - {} + { + node->removeAndDestroyAllChildren(); + mSceneMgr->destroySceneNode(node); + } + + // TODO: We could make allocation a little more refined than new and + // delete. But that's true for everything here. A freelist based + // approach is best in most of these cases, as we have continuous + // allocation/deallocation of fixed-size structs. + Ogre::AxisAlignedBox *terr_makeBounds(float minHeight, float maxHeight, + float width, SceneNode* node) + { + AxisAlignedBox *mBounds = new AxisAlignedBox; + + mBounds->setExtents(0,0,minHeight, + width,width,maxHeight); - void *terr_makeBounds(float minHeight, float maxHeight, - float width) - {} + // Transform the box to world coordinates, so it can be compared + // with the camera later. + mBounds->transformAffine(node->_getFullTransform()); - float terr_getSqCamDist(void*) - {} + return mBounds; + } - void *terr_makeMesh(int segment, SceneNode*) - {} + void terr_killBounds(AxisAlignedBox *bounds) + { + delete bounds; + } - void terr_killMesh(void*) - {} + float terr_getSqCamDist(AxisAlignedBox *mBounds) + { + Ogre::Vector3 cpos = mCamera->getDerivedPosition(); + Ogre::Vector3 diff(0, 0, 0); + diff.makeFloor(cpos - mBounds->getMinimum() ); + diff.makeCeil(cpos - mBounds->getMaximum() ); + return diff.squaredLength(); + } + + TerrainMesh *terr_makeMesh(SceneNode *parent, + MeshInfo *info, + int level, float scale) + { + + return new TerrainMesh(parent, *info, level, scale); + } + + void terr_killMesh(TerrainMesh *mesh) + { delete mesh; } // Set up the rendering system void terr_setupRendering() { + // Make sure the C++ sizes match the D sizes, since the structs + // will be shared between the two. + assert(sizeof(MeshInfo) == 17*4); + assert(sizeof(AlphaInfo) == 6*4); + + // Add the terrain directory as a resource location. TODO: Get the + // name from D. + ResourceGroupManager::getSingleton(). + addResourceLocation("cache/terrain/", "FileSystem", "General"); + + // Enter superman mode + mCamera->setFarClipDistance(32*CELL_WIDTH); + //ogre_setFog(0.7, 0.7, 0.7, 200, 32*CELL_WIDTH); + d_terr_superman(); + // Create a root scene node first. The 'root' node is rotated to // match the MW coordinate system - g_rootTerrainNode = root->createChildSceneNode("TERRAIN_ROOT"); + g_rootTerrainNode = mwRoot->createChildSceneNode("TERRAIN_ROOT"); // Add the base land. This is the ground beneath the actual // terrain mesh that makes the terrain look infinite. - g_baseLand = new BaseLand(g_rootTerrainNode); - - /* - // Add the terrain directory - ResourceGroupManager::getSingleton(). - addResourceLocation(g_cacheDir, "FileSystem", "General"); - - // Open the archive file - g_archive.openFile(g_cacheFile); - - // Create the root quad. - g_rootQuad = new Quad(); - */ + g_baseLand = new BaseLand(); // Add the frame listener mRoot->addFrameListener(new TerrainFrameListener); - - // Enter superman mode - mCamera->setFarClipDistance(32*CELL_WIDTH); - //ogre_setFog(0.7, 0.7, 0.7, 200, 32*CELL_WIDTH); - d_superman(); } } diff --git a/terrain/generator.d b/terrain/generator.d index e40003081..3c0c955e2 100644 --- a/terrain/generator.d +++ b/terrain/generator.d @@ -24,18 +24,16 @@ // This module is responsible for generating the cache files. module terrain.generator; -/+ import std.stdio; import std.string; import terrain.cachewriter; import terrain.esmland; +import terrain.terrain; import util.cachefile; const float TEX_SCALE = 1.0/16; -char[] cacheDir = "cache/terrain/"; - int mCount; // Texture sizes for the various levels. For the most detailed level @@ -43,21 +41,18 @@ int mCount; // than a final texture. int[] texSizes; -// Default textures -GenLevelResult[] defaults; - CacheWriter cache; -void generate() +void generate(char[] filename) { makePath(cacheDir); - cache.openFile(filename); + //cache.openFile(filename); // Find the maxiumum distance from (0,0) in any direction int max = mwland.getMaxCoord(); - // Round up to nearest binary + // Round up to nearest power of 2 int depth=1; while(max) { @@ -73,7 +68,7 @@ void generate() // Set the texture sizes. TODO: These should be config options, // perhaps - or maybe a result of some higher-level detail setting. - texSizes.resize(depth+1, 0); + texSizes.length = depth+1; texSizes[6] = 1024; texSizes[5] = 512; texSizes[4] = 256; @@ -81,9 +76,12 @@ void generate() texSizes[2] = 256; texSizes[1] = 64; + writefln("Data generation not implemented yet"); + // Set some general parameters for the runtime cache.setParams(depth+1, texSizes[1]); + /* // Create some common data first writefln("Generating common data"); genDefaults(); @@ -97,8 +95,14 @@ void generate() writefln("Writing index file"); cache.finish(); writefln("Pregeneration done. Results written to ", filename); + */ } +/+ + +// Default textures +GenLevelResult[] defaults; + // Generates the default texture images "2_default.png" etc void genDefaults() { diff --git a/terrain/quad.d b/terrain/quad.d index 1642f3625..17e385878 100644 --- a/terrain/quad.d +++ b/terrain/quad.d @@ -40,12 +40,6 @@ class Quad mNode = terr_createChildNode(relX*CELL_WIDTH, relY*CELL_WIDTH, parent.mNode); - /* - Ogre::Vector3 pos(relX * CELL_WIDTH, - relY * CELL_WIDTH, - 0); - mNode = parent.mNode.createChildSceneNode(pos); - */ // Get the archive data for this quad. mInfo = g_archive.getQuad(mCellX,mCellY,mLevel); @@ -63,10 +57,6 @@ class Quad mNode = terr_createChildNode(cellX*CELL_WIDTH, cellY*CELL_WIDTH, null); - /* - mNode = g_rootTerrainNode. - createChildSceneNode(pos); - */ // Split up split(); @@ -78,20 +68,12 @@ class Quad assert(mLevel >= 1); assert(mNode !is null); - // TODO: How do we store the C++ bounding box? + // Set up the bounding box. Use MW coordinates all the way mBounds = terr_makeBounds(mInfo.minHeight, mInfo.maxHeight, - mInfo.worldWidth); - /* - // Set up the bounding box. Use MW coordinates all the way - mBounds.setExtents(0,0,mInfo.minHeight, - mInfo.worldWidth,mInfo.worldWidth, - mInfo.maxHeight); - - // Transform the box to world coordinates, so it can be compared - // with the camera later. - mBounds.transformAffine(mNode._getFullTransform()); - */ + mInfo.worldWidth, + mNode); + float radius = mInfo.boundingRadius; mSplitDistance = radius * SPLIT_FACTOR; @@ -119,10 +101,7 @@ class Quad delete mChildren[i]; terr_destroyNode(mNode); - /* - mNode.removeAndDestroyAllChildren(); - mSceneMgr.destroySceneNode(mNode); - */ + terr_killBounds(mBounds); } // Remove the landscape for this quad, and create children. @@ -187,15 +166,6 @@ class Quad // Get (squared) camera distance. TODO: shouldn't this just // be a simple vector difference from the mesh center? float camDist = terr_getSqCamDist(mBounds); - /* - { - Ogre::Vector3 cpos = mCamera.getDerivedPosition(); - Ogre::Vector3 diff(0, 0, 0); - diff.makeFloor(cpos - mBounds.getMinimum() ); - diff.makeCeil(cpos - mBounds.getMaximum() ); - camDist = diff.squaredLength(); - } - */ // No children? if(!hasChildren) @@ -249,7 +219,10 @@ class Quad // care of the loading. meshList.length = mInfo.meshNum; foreach(i, ref m; meshList) - m = terr_makeMesh(i, mNode); + { + MeshInfo *mi = g_archive.getMeshInfo(i); + m = terr_makeMesh(mNode, mi, mInfo.level, mInfo.texScale); + } hasMesh = true; } @@ -275,7 +248,6 @@ class Quad // Bounding box, transformed to world coordinates. Used to calculate // camera distance. - //Ogre::AxisAlignedBox mBounds; Bounds mBounds; float mSplitDistance,mUnsplitDistance; diff --git a/terrain/terrain.d b/terrain/terrain.d index fdad3eac3..66fc70f67 100644 --- a/terrain/terrain.d +++ b/terrain/terrain.d @@ -24,14 +24,41 @@ module terrain.terrain; import terrain.generator; +import terrain.archive; import terrain.bindings; +import terrain.quad; +import std.file, std.stdio; + +char[] cacheDir = "cache/terrain/"; void initTerrain(bool doGen) { - /* + char[] fname = cacheDir ~ "landscape.cache"; + + if(!exists(fname)) + { + writefln("Cache file '%s' not found. Creating:", + fname); + doGen = true; + } + if(doGen) - generate(); - */ + generate(fname); + + // Load the archive file + g_archive.openFile(fname); terr_setupRendering(); + + // Create the root quad + rootQuad = new Quad; } + +extern(C) void d_terr_terrainUpdate() +{ + // Update the root quad each frame. + assert(rootQuad !is null); + rootQuad.update(); +} + +Quad rootQuad;