From 401bd35e02f48a5fb68995346e1c47343547f4e5 Mon Sep 17 00:00:00 2001 From: nkorslund Date: Sat, 16 May 2009 20:13:33 +0000 Subject: [PATCH] Further cut down the number of classes git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@115 ea6a568a-9f4f-0410-981a-c910a81bb256 --- Makefile | 2 +- terrain/cpp_framelistener.cpp | 3 +- terrain/cpp_heightmap.cpp | 17 +- terrain/cpp_heightmap2.cpp | 24 -- terrain/cpp_terrain.cpp | 8 +- terrain/cpp_terrainmesh.cpp | 505 +++++++++++++++++++++++++++++++--- terrain/cpp_terrainmesh2.cpp | 495 --------------------------------- 7 files changed, 487 insertions(+), 567 deletions(-) delete mode 100644 terrain/cpp_heightmap2.cpp delete mode 100644 terrain/cpp_terrainmesh2.cpp diff --git a/Makefile b/Makefile index 5a4e348ff..5cb0b2246 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ mygui_cpp=mygui console # Ditto for the landscape engine, in terrain/cpp_X.cpp terrain_cpp=baseland esm framelistener generator index landdata\ materialgen heightmap palette point2\ -quad quaddata terrain terrainmesh terrainmesh2 heightmap2 +quad quaddata terrain terrainmesh # FFmpeg files, in the form sound/cpp_X.cpp. avcodec_cpp=avcodec diff --git a/terrain/cpp_framelistener.cpp b/terrain/cpp_framelistener.cpp index 9323fb97b..45920519c 100644 --- a/terrain/cpp_framelistener.cpp +++ b/terrain/cpp_framelistener.cpp @@ -6,6 +6,7 @@ protected: */ bool frameEnded(const FrameEvent& evt) { + g_rootQuad->update(evt.timeSinceLastFrame); g_heightMap->update(evt.timeSinceLastFrame); return true; } @@ -29,7 +30,7 @@ public: g_heightMap->setTextureFadingEnabled(false); //create the quad node - g_heightMap->create(); + g_rootQuad = new Quad(Quad::QL_ROOT, 0); } /* KILLME diff --git a/terrain/cpp_heightmap.cpp b/terrain/cpp_heightmap.cpp index 2bc5844e4..b39f806e4 100644 --- a/terrain/cpp_heightmap.cpp +++ b/terrain/cpp_heightmap.cpp @@ -1,9 +1,12 @@ class HeightMap { public: - HeightMap(Ogre::SceneNode* r); - - ~HeightMap(); + HeightMap(Ogre::SceneNode* r) + : mTerrainSceneNode(r), + mMorphingEnabled(false), + mTextureFadingEnabled(false), + mBaseLand(r) + {} /** * loads the quad data from the disk @@ -54,11 +57,12 @@ public: return true; } - void create(); - inline Ogre::SceneNode* getTerrainSceneNode(){return mTerrainSceneNode;} - void update(Ogre::Real t); + void update(Ogre::Real t) + { + mBaseLand.update(); + } inline Ogre::Real getMorphSpeed(){return 1.0f;} inline Ogre::Real getTextureFadeSpeed(){ return 2.0f;} @@ -80,7 +84,6 @@ public: private: Ogre::SceneNode* mTerrainSceneNode; - Quad* mQuadRoot; bool mMorphingEnabled; bool mTextureFadingEnabled; diff --git a/terrain/cpp_heightmap2.cpp b/terrain/cpp_heightmap2.cpp deleted file mode 100644 index bae9809a1..000000000 --- a/terrain/cpp_heightmap2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -HeightMap::HeightMap(Ogre::SceneNode* r) - : mTerrainSceneNode(r), - mQuadRoot(0), - mMorphingEnabled(true), - mTextureFadingEnabled(true), - mBaseLand(r) -{ - -} -//---------------------------------------------- -HeightMap::~HeightMap(){ - delete mQuadRoot; -} -//---------------------------------------------- -void HeightMap::create(){ - mQuadRoot = new Quad(Quad::QL_ROOT, 0); -} -//---------------------------------------------- -void HeightMap::update(Ogre::Real t){ - assert(mQuadRoot); - mQuadRoot->update(t); - mBaseLand.update(); -} - diff --git a/terrain/cpp_terrain.cpp b/terrain/cpp_terrain.cpp index 0bb8fd668..6ba14603c 100644 --- a/terrain/cpp_terrain.cpp +++ b/terrain/cpp_terrain.cpp @@ -56,8 +56,10 @@ class Quad; class QuadData; class MaterialGenerator; class HeightMap; +class TerrainMesh; HeightMap *g_heightMap; +Quad *g_rootQuad; MaterialGenerator *g_materialGen; #undef TRACE @@ -89,15 +91,9 @@ MaterialGenerator *g_materialGen; // For rendering #include "cpp_baseland.cpp" - -// These depend on each other, so our usual hackery won't work. We -// need the header files first. #include "cpp_heightmap.cpp" #include "cpp_terrainmesh.cpp" #include "cpp_quad.cpp" -#include "cpp_heightmap2.cpp" -#include "cpp_terrainmesh2.cpp" - #include "cpp_framelistener.cpp" TerrainFrameListener terrainListener; diff --git a/terrain/cpp_terrainmesh.cpp b/terrain/cpp_terrainmesh.cpp index 03ec0610f..f56bf8548 100644 --- a/terrain/cpp_terrainmesh.cpp +++ b/terrain/cpp_terrainmesh.cpp @@ -4,35 +4,159 @@ #define QSDEBUG class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject { - public: +public: TerrainMesh(QuadData* qd, float segSize, float startX, float startY, const Ogre::Vector3 &pos, int width, int depth, bool skirts, - Ogre::SceneNode *parent); + Ogre::SceneNode *parent) + : Ogre::Renderable(), + Ogre::MovableObject(), + mWidth(width), + mUseSkirts(skirts), + mBuilt(false), + mDepth(depth), + mVertexes(0), + mIndices(0), + mLODMorphFactor(0), + mTextureFadeFactor(0), + mMin(30000), + mMax(-30000), + mExtraMorphAmount(0), + mHasFadePass(false), + mQuadData(qd), + mSegmentSize(segSize), + mX(startX), + mY(startY) + { + // From QuadSegment() + assert(qd); + assert(segSize>0&&segSize<=1); + assert(mY>=0&&mY<=1); + assert(mX>=0&&mY<=1); - ~TerrainMesh() +#ifdef QSDEBUG { - destroy(); + //check sizes + const float qw = mQuadData->getVertexWidth()-1; + const float fsw = qw*segSize; + const int isw = (int)fsw; + assert(fsw==isw); + } +#endif + + //precalc offsets, as getVertex/getNormal get called a lot (1000s of times) + computeOffsets(); + + // From Quad + node = parent->createChildSceneNode(pos); + + // From create() + createVertexBuffer(); + calculateVertexValues(); + calculateIndexValues(); + setBounds(); + + node->attachObject(this); + + createMaterial(); + + if ( g_heightMap->isMorphingEnabled() && + mDepth != g_heightMap->getMaxDepth() ) + { + Ogre::Technique* tech = getMaterial()->getTechnique(0); + for ( size_t i = 0; i < tech->getNumPasses(); ++i ) + { + assert(g_heightMap->isMorphingEnabled()); + tech->getPass(i)->setVertexProgram(MORPH_VERTEX_PROGRAM); + } + } + + if ( g_heightMap->isMorphingEnabled() ) + calculateDeltaValues(); + + mBuilt = true; + } + + ~TerrainMesh() + { + if ( !mBuilt ) return; - assert(node); + //deleting null values is fine iirc + delete mIndices; - node->detachAllObjects(); - node->getCreator()->destroySceneNode(node); +# if ENABLED_CRASHING == 1 + { + delete mVertexes; + } +# else + { + if ( mDepth != g_heightMap->getMaxDepth() ){ + delete mVertexes; + } } +# endif - /** - * Can be called manually and can be called from the destuctor. This - * destroyes the mesh - */ - // FIXME: We don't need this as a separate function. - void destroy(); + mBuilt = false; + + assert(node); + + node->detachAllObjects(); + node->getCreator()->destroySceneNode(node); + } /** * @brief Checks if it needs to be split or unsplit and deals with * the morph factor. time seconds since last frame */ - void update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist); + void update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist) + { + TRACE("TerrainMesh::update"); + //if ( USE_MORPH ){ + + //as aprocesh mUnsplitDistance, lower detail + if ( camDist > morphDist && mDepth > 1 ) { + mLODMorphFactor = 1 - (usplitDist - camDist)/(usplitDist-morphDist); + } else + mLODMorphFactor = 0; + mTextureFadeFactor = mLODMorphFactor; + + + //on an split, it sets the extra morph amount to 1, we then ensure this ends up at 0... slowly + if ( mExtraMorphAmount > 0 ) { + mLODMorphFactor += mExtraMorphAmount; + mExtraMorphAmount -= (time/g_heightMap->getMorphSpeed()); //decrease slowly + } + if ( mExtraFadeAmount > 0 ) { + mTextureFadeFactor += mExtraFadeAmount; + mExtraFadeAmount -= (time/g_heightMap->getTextureFadeSpeed()); + } + + //Ensure within valid bounds + if ( mLODMorphFactor > 1 ) + mLODMorphFactor = 1; + else if ( mLODMorphFactor < 0 ) + mLODMorphFactor = 0; + + if ( mTextureFadeFactor > 1 ) + mTextureFadeFactor = 1; + else if ( mTextureFadeFactor < 0 ) + mTextureFadeFactor = 0; + + //} + + //remove pass. Keep outside in case terrain fading is removed while it is active + if ( mHasFadePass && mTextureFadeFactor == 0 ) { + removeFadePass(); + } else if ( g_heightMap->isTextureFadingEnabled() && + !mHasFadePass && + mTextureFadeFactor > 0 && + hasParentTexture() ) { + addFadePass(); + } + + } + /** * @todo Needs to work out what this does (if it does what it is meant to) @@ -106,17 +230,36 @@ class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject * @brief passes the morph factor to the custom vertex program */ void _updateCustomGpuParameter(const Ogre::GpuProgramParameters::AutoConstantEntry& constantEntry, - Ogre::GpuProgramParameters* params) const; + Ogre::GpuProgramParameters* params) const + { + using namespace Ogre; + if (constantEntry.data == MORPH_CUSTOM_PARAM_ID) + params->_writeRawConstant(constantEntry.physicalIndex, mLODMorphFactor); + else if ( constantEntry.data == FADE_CUSTOM_PARAM_ID ) + params->_writeRawConstant(constantEntry.physicalIndex, mTextureFadeFactor); + else + Renderable::_updateCustomGpuParameter(constantEntry, params); + } + /** * @brief sets the mExtraMorphAmount so it slowly regains detail from the lowest morph factor */ - void justSplit(); + void justSplit() + { + mExtraMorphAmount = 1; + mLODMorphFactor = 1; + mTextureFadeFactor = 1; + mExtraFadeAmount = 1; + + if ( g_heightMap->isTextureFadingEnabled() && hasParentTexture() ) + addFadePass(); + } + /** * @brief Does nothing */ - inline void justUnsplit(){ - } + inline void justUnsplit(){} inline float getMax(){ return mMax; @@ -138,7 +281,7 @@ class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject /** * @brief gets a vertex assuming that x = 0, y = 0 addresses the start of the quad */ - float getVertex(int x, int y) + float getVertexHeight(int x, int y) { #ifdef QSDEBUG { @@ -155,7 +298,7 @@ class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject return mQuadData->getNormal(((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x))*3+z); } - private: +private: void createMaterial() { @@ -217,48 +360,331 @@ class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject /** * @brief Adds another pass to the material to fade in/out the material from a higher level */ - void addFadePass(); + void addFadePass() + { + assert(mHasFadePass==false); + + if ( mDepth == g_heightMap->getMaxDepth() ) return; + + + mHasFadePass = true; + Ogre::MaterialPtr mat = getMaterial(); + Ogre::Pass* newPass = mat->getTechnique(0)->createPass(); + newPass->setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); + + //set fragment program + assert(g_heightMap->isTextureFadingEnabled()); + newPass->setFragmentProgram(FADE_FRAGMENT_PROGRAM); + + if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) { + assert(g_heightMap->isMorphingEnabled()); + newPass->setVertexProgram(MORPH_VERTEX_PROGRAM); + } + + + //set texture to be used + newPass->createTextureUnitState(getParentTexture(), 1); + } + /** * @brief removes the last pass from the material. Assumed to be the fade pass */ - void removeFadePass(); + void removeFadePass() + { + assert(mHasFadePass==true); + mHasFadePass = false; + Ogre::MaterialPtr mat = getMaterial(); + Ogre::Technique* tech = mat->getTechnique(0); - /** - * @return the height at the given vertex - */ - float getVertexHeight(int x, int y); + tech->removePass(tech->getNumPasses()-1); + } /** * Inits the vertex stuff */ - void createVertexBuffer(); + void createVertexBuffer() + { + using namespace Ogre; + + size_t vw = mWidth; + if ( mUseSkirts ) vw += 2; + + mVertexes = new VertexData(); + mVertexes->vertexStart = 0; + mVertexes->vertexCount = vw*vw;// VERTEX_WIDTH; + + VertexDeclaration* vertexDecl = mVertexes->vertexDeclaration; + size_t currOffset = 0; + + vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_POSITION); + currOffset += VertexElement::getTypeSize(VET_FLOAT3); + + vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_NORMAL); + currOffset += VertexElement::getTypeSize(VET_FLOAT3); + + + vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); + currOffset += VertexElement::getTypeSize(VET_FLOAT2); + + if ( g_heightMap->isTextureFadingEnabled() ) { + vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 1); + currOffset += VertexElement::getTypeSize(VET_FLOAT2); + } + + mMainBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( + vertexDecl->getVertexSize(0), // size of one whole vertex + mVertexes->vertexCount, // number of vertices + HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage + false); // no shadow buffer + + mVertexes->vertexBufferBinding->setBinding(MAIN_BINDING, mMainBuffer); //bind the data + + if ( g_heightMap->isMorphingEnabled() ) + vertexDecl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS); + + + } + /** * @brief fills the vertex buffer with data * @todo I don't think tex co-ords are right */ - void calculateVetexValues(); + void calculateVertexValues() + { + //get the texture offsets for the higher uv + float xUVOffset = 0; + float yUVOffset = 0; + + if ( g_heightMap->isTextureFadingEnabled() ) { + assert(0); + } + + int start = 0; + int end = mWidth; + + if ( mUseSkirts ) + { + --start; + ++end; + } + + float* verts = static_cast(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD)); + for ( int y = start; y < end; y++ ) { + for ( int x = start; x < end; x++ ) { + + //the skirts + if ( y < 0 || y > (mWidth-1) || x < 0 || x > (mWidth-1) ) { + + if ( x < 0 ) *verts++ = 0; + else if ( x > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation(); + else *verts++ = x*getVertexSeperation(); + + *verts++ = -4096; //2048 below base sea floor height + + if ( y < 0 ) *verts++ = 0; + else if ( y > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation(); + else *verts++ = y*getVertexSeperation(); + + + for ( Ogre::uint i = 0; i < 3; i++ ) + *verts++ = 0; + + float u = (float)(x) / (mWidth-1); + float v = (float)(y) / (mWidth-1); + + //clamped, so shouldn't matter if > 1 + + *verts++ = u; + *verts++ = v; + + if ( g_heightMap->isTextureFadingEnabled() ) { + *verts++ = u; + *verts++ = v; + } + } else { + + assert(y*mWidth+x>=0&&y*mWidth+xgetNormal((y*mWidth+x)*3+i); + + const float u = (float)(x) / (mWidth-1); + const float v = (float)(y) / (mWidth-1); + assert(u>=0&&v>=0); + assert(u<=1&&v<=1); + + *verts++ = u; + *verts++ = v; + + if ( g_heightMap->isTextureFadingEnabled() ) { + *verts++ = u/2.0f + xUVOffset; + *verts++ = v/2.0f + yUVOffset; + } + } + } + } + mMainBuffer->unlock(); + } /** * @brief returns a a new Vertex Buffer ready for input * @remarks Unlike other terrain libs, this isn't 0s when it is returend */ - Ogre::HardwareVertexBufferSharedPtr createDeltaBuffer( ); + Ogre::HardwareVertexBufferSharedPtr createDeltaBuffer() + { + size_t vw = mWidth; + if ( mUseSkirts ) vw += 2; + + const size_t totalVerts = (vw * vw); + return Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( + Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT1), + totalVerts, + Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, + false); //no shadow buff + + } + + /** * @brief DOESN'T WORK FULLY * @todo fix */ - void calculateDeltaValues(); +#define SET_DELTA_AT(x, y, v) \ +if ( mUseSkirts ) pDeltas[( y + 1)*vw+ x + 1] = v; \ +else pDeltas[( y)*vw+ x] = v; + void calculateDeltaValues() + { + assert(0); + /* + size_t vw = mWidth; + if ( mUseSkirts ) vw += 2; + + //must be using morphing to use this function + assert(g_heightMap->isMorphingEnabled()); + + const size_t step = 2; + + // Create a set of delta values + mDeltaBuffer = createDeltaBuffer(); + float* pDeltas = static_cast(mDeltaBuffer->lock(HardwareBuffer::HBL_DISCARD)); + memset(pDeltas, 0, (vw)*(vw) * sizeof(float)); + + return; + + bool flag=false; + for ( size_t y = 0; y < mWidth-step; y += step ) { + for ( size_t x = 0; x < mWidth-step; x += step ) { + //create the diffrence between the full vertex if the vertex wasn't their + + float bottom_left = getVertexHeight(x,y); + float bottom_right = getVertexHeight(x+step,y); + + float top_left = getVertexHeight(x,y+step); + float top_right = getVertexHeight(x+step,y+step); + + //const int vw = mWidth+2; + SET_DELTA_AT(x, y+1, (bottom_left+top_left)/2 - getVertexHeight(x, y+1)) //left + SET_DELTA_AT(x+2, y+1, (bottom_right+top_right)/2 - getVertexHeight(x+2, y+1)) //right + + SET_DELTA_AT(x+1, y+2, (top_right+top_left)/2 - getVertexHeight(x+1, y+2)) //top + SET_DELTA_AT(x+1, y, (bottom_right+bottom_left)/2 - getVertexHeight(x+1, y)) //bottom + + //this might not be correct + if ( !flag ) + SET_DELTA_AT(x+1, y+1, (bottom_left+top_right)/2 - getVertexHeight(x+1, y+1)) //center + else + SET_DELTA_AT(x+1, y+1, (bottom_right+top_left)/2 - getVertexHeight(x+1, y+1)) //center + + flag = !flag; + } + flag = !flag; //flip tries for next row + } + + mDeltaBuffer->unlock(); + mVertexes->vertexBufferBinding->setBinding(DELTA_BINDING,mDeltaBuffer); + */ + } +#undef SET_DELTA_AT + /** * @brief gets the position of a vertex. It will not interpolate */ - Ogre::Vector3 getVertexPosition(int x, int y); + Ogre::Vector3 getVertexPosition(int x, int y) + { + return Ogre::Vector3(x*getVertexSeperation(), getVertexHeight(x,y) , y*getVertexSeperation()); + } /** * @brief gets the indicies for the vertex data. */ - void calculateIndexValues(); + void calculateIndexValues() + { + size_t vw = mWidth-1; + if ( mUseSkirts ) vw += 2; + + const size_t indexCount = (vw)*(vw)*6; + + //need to manage allocation if not null + assert(mIndices==0); + + mIndices = new IndexData(); + mIndices->indexCount = indexCount; + mIndices->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( + HardwareIndexBuffer::IT_16BIT, + indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); + + unsigned short* indices = static_cast(mIndices->indexBuffer->lock(0, + mIndices->indexBuffer->getSizeInBytes(), + HardwareBuffer::HBL_DISCARD)); + + bool flag = false; + Ogre::uint indNum = 0; + for ( Ogre::uint y = 0; y < (vw); y+=1 ) { + for ( Ogre::uint x = 0; x < (vw); x+=1 ) { + + const int line1 = y * (vw+1) + x; + const int line2 = (y + 1) * (vw+1) + x; + + if ( flag ) { + *indices++ = line1; + *indices++ = line2; + *indices++ = line1 + 1; + + *indices++ = line1 + 1; + *indices++ = line2; + *indices++ = line2 + 1; + } else { + *indices++ = line1; + *indices++ = line2; + *indices++ = line2 + 1; + + *indices++ = line1; + *indices++ = line2 + 1; + *indices++ = line1 + 1; + } + flag = !flag; //flip tris for next time + + indNum+=6; + } + flag = !flag; //flip tries for next row + } + assert(indNum==indexCount); + mIndices->indexBuffer->unlock(); + //return mIndices; + } + /* * Sets the bounds on the renderable. This requires that mMin/mMax @@ -266,7 +692,20 @@ class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject * as though it is done twice, as it is also done in MeshInterface, * however, there is no guarentee that the mesh sizes are the same */ - void setBounds(); + void setBounds() + { + mBounds.setExtents(0,mMin,0, + (mWidth - 1) * getVertexSeperation(), + mMax, + (mWidth - 1) * getVertexSeperation()); + + mCenter = Ogre::Vector3( ( (mWidth - 1) * getVertexSeperation() ) / 2, + ( mMin + mMax ) / 2, + ( (mWidth - 1) * getVertexSeperation() ) / 2); + + mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2; + } + Ogre::SceneNode* node; diff --git a/terrain/cpp_terrainmesh2.cpp b/terrain/cpp_terrainmesh2.cpp deleted file mode 100644 index caa5f4558..000000000 --- a/terrain/cpp_terrainmesh2.cpp +++ /dev/null @@ -1,495 +0,0 @@ -TerrainMesh::TerrainMesh(QuadData* qd, float segSize, float startX, float startY, - const Ogre::Vector3 &pos, - int width, int depth, bool skirts, - Ogre::SceneNode *parent) - : Ogre::Renderable(), - Ogre::MovableObject(), - mWidth(width), - mUseSkirts(skirts), - mBuilt(false), - mDepth(depth), - mVertexes(0), - mIndices(0), - mLODMorphFactor(0), - mTextureFadeFactor(0), - mMin(30000), - mMax(-30000), - mExtraMorphAmount(0), - mHasFadePass(false), - mQuadData(qd), - mSegmentSize(segSize), - mX(startX), - mY(startY) -{ - // From QuadSegment() - assert(qd); - assert(segSize>0&&segSize<=1); - assert(mY>=0&&mY<=1); - assert(mX>=0&&mY<=1); - -#ifdef QSDEBUG - { - //check sizes - const float qw = mQuadData->getVertexWidth()-1; - const float fsw = qw*segSize; - const int isw = (int)fsw; - assert(fsw==isw); - } -#endif - - //precalc offsets, as getVertex/getNormal get called a lot (1000s of times) - computeOffsets(); - - // From Quad - node = parent->createChildSceneNode(pos); - - // From create() - createVertexBuffer(); - calculateVetexValues(); - calculateIndexValues(); - setBounds(); - - node->attachObject(this); - - createMaterial(); - - if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) { - Ogre::Technique* tech = getMaterial()->getTechnique(0); - for ( size_t i = 0; i < tech->getNumPasses(); ++i ) { - assert(g_heightMap->isMorphingEnabled()); - tech->getPass(i)->setVertexProgram(MORPH_VERTEX_PROGRAM); - } - } - - if ( g_heightMap->isMorphingEnabled() ) - calculateDeltaValues(); - - mBuilt = true; -} - -void TerrainMesh::destroy() { - if ( !mBuilt ) return; - - //deleting null values is fine iirc - delete mIndices; - -# if ENABLED_CRASHING == 1 - { - delete mVertexes; - } -# else - { - if ( mDepth != g_heightMap->getMaxDepth() ){ - delete mVertexes; - } - } -# endif - - mBuilt = false; -} -//---------------------------------------------- -void TerrainMesh::update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist) -{ - TRACE("TerrainMesh::update"); - //if ( USE_MORPH ){ - - //as aprocesh mUnsplitDistance, lower detail - if ( camDist > morphDist && mDepth > 1 ) { - mLODMorphFactor = 1 - (usplitDist - camDist)/(usplitDist-morphDist); - } else - mLODMorphFactor = 0; - mTextureFadeFactor = mLODMorphFactor; - - - //on an split, it sets the extra morph amount to 1, we then ensure this ends up at 0... slowly - if ( mExtraMorphAmount > 0 ) { - mLODMorphFactor += mExtraMorphAmount; - mExtraMorphAmount -= (time/g_heightMap->getMorphSpeed()); //decrease slowly - } - if ( mExtraFadeAmount > 0 ) { - mTextureFadeFactor += mExtraFadeAmount; - mExtraFadeAmount -= (time/g_heightMap->getTextureFadeSpeed()); - } - - //Ensure within valid bounds - if ( mLODMorphFactor > 1 ) - mLODMorphFactor = 1; - else if ( mLODMorphFactor < 0 ) - mLODMorphFactor = 0; - - if ( mTextureFadeFactor > 1 ) - mTextureFadeFactor = 1; - else if ( mTextureFadeFactor < 0 ) - mTextureFadeFactor = 0; - - //} - - //remove pass. Keep outside in case terrain fading is removed while it is active - if ( mHasFadePass && mTextureFadeFactor == 0 ) { - removeFadePass(); - } else if ( g_heightMap->isTextureFadingEnabled() && - !mHasFadePass && - mTextureFadeFactor > 0 && - hasParentTexture() ) { - addFadePass(); - } - -} -//---------------------------------------------- -void TerrainMesh::addFadePass() { - assert(mHasFadePass==false); - - if ( mDepth == g_heightMap->getMaxDepth() ) return; - - - mHasFadePass = true; - Ogre::MaterialPtr mat = getMaterial(); - Ogre::Pass* newPass = mat->getTechnique(0)->createPass(); - newPass->setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); - - //set fragment program - assert(g_heightMap->isTextureFadingEnabled()); - newPass->setFragmentProgram(FADE_FRAGMENT_PROGRAM); - - if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) { - assert(g_heightMap->isMorphingEnabled()); - newPass->setVertexProgram(MORPH_VERTEX_PROGRAM); - } - - - //set texture to be used - newPass->createTextureUnitState(getParentTexture(), 1); -} -//---------------------------------------------- -void TerrainMesh::removeFadePass() { - assert(mHasFadePass==true); - mHasFadePass = false; - Ogre::MaterialPtr mat = getMaterial(); - Ogre::Technique* tech = mat->getTechnique(0); - - tech->removePass(tech->getNumPasses()-1); -} -//---------------------------------------------- -void TerrainMesh::justSplit() { - mExtraMorphAmount = 1; - mLODMorphFactor = 1; - mTextureFadeFactor = 1; - mExtraFadeAmount = 1; - - if ( g_heightMap->isTextureFadingEnabled() && hasParentTexture() ) - addFadePass(); -} - -//---------------------------------------------- -void TerrainMesh::_updateCustomGpuParameter( - const GpuProgramParameters::AutoConstantEntry& constantEntry, - GpuProgramParameters* params) const { - using namespace Ogre; - if (constantEntry.data == MORPH_CUSTOM_PARAM_ID) - params->_writeRawConstant(constantEntry.physicalIndex, mLODMorphFactor); - else if ( constantEntry.data == FADE_CUSTOM_PARAM_ID ) - params->_writeRawConstant(constantEntry.physicalIndex, mTextureFadeFactor); - else - Renderable::_updateCustomGpuParameter(constantEntry, params); - - -} -//---------------------------------------------- -float TerrainMesh::getVertexHeight(int x, int y) { - return getVertex(x,y); -} -//---------------------------------------------- -Ogre::Vector3 TerrainMesh::getVertexPosition(int x, int y) { - return Ogre::Vector3(x*getVertexSeperation(), getVertexHeight(x,y) , y*getVertexSeperation()); -} -//---------------------------------------------- -void TerrainMesh::calculateVetexValues() { - using namespace Ogre; - - //get the texture offsets for the higher uv - float xUVOffset = 0; - float yUVOffset = 0; - - if ( g_heightMap->isTextureFadingEnabled() ) { - assert(0); - } - /* - switch (mInterface->getLocation()) { - case Quad::QL_NW : - yUVOffset = 32.0f/64.0f; - break; - case Quad::QL_NE: - yUVOffset = 32.0f/64.0f; - xUVOffset = 32.0f/64.0f; - break; - case Quad::QL_SE: - xUVOffset = 32.0f/64.0f; - break; - default: - break; - } - */ - - int start = 0; - int end = mWidth; - - if ( mUseSkirts ) { - --start; - ++end; - } - - float* verts = static_cast(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD)); - for ( int y = start; y < end; y++ ) { - for ( int x = start; x < end; x++ ) { - - //the skirts - if ( y < 0 || y > (mWidth-1) || x < 0 || x > (mWidth-1) ) { - - if ( x < 0 ) *verts++ = 0; - else if ( x > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation(); - else *verts++ = x*getVertexSeperation(); - - *verts++ = -4096; //2048 below base sea floor height - - if ( y < 0 ) *verts++ = 0; - else if ( y > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation(); - else *verts++ = y*getVertexSeperation(); - - - for ( Ogre::uint i = 0; i < 3; i++ ) - *verts++ = 0; - - float u = (float)(x) / (mWidth-1); - float v = (float)(y) / (mWidth-1); - - //clamped, so shouldn't matter if > 1 - - *verts++ = u; - *verts++ = v; - - if ( g_heightMap->isTextureFadingEnabled() ) { - *verts++ = u; - *verts++ = v; - } - } else { - - assert(y*mWidth+x>=0&&y*mWidth+xgetNormal((y*mWidth+x)*3+i); - - const float u = (float)(x) / (mWidth-1); - const float v = (float)(y) / (mWidth-1); - assert(u>=0&&v>=0); - assert(u<=1&&v<=1); - - *verts++ = u; - *verts++ = v; - - if ( g_heightMap->isTextureFadingEnabled() ) { - *verts++ = u/2.0f + xUVOffset; - *verts++ = v/2.0f + yUVOffset; - } - } - } - } - mMainBuffer->unlock(); -} -//---------------------------------------------- -void TerrainMesh::setBounds() { - mBounds.setExtents(0,mMin,0, - (mWidth - 1) * getVertexSeperation(), - mMax, - (mWidth - 1) * getVertexSeperation()); - - mCenter = Ogre::Vector3( ( (mWidth - 1) * getVertexSeperation() ) / 2, - ( mMin + mMax ) / 2, - ( (mWidth - 1) * getVertexSeperation() ) / 2); - - mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2; -} -//---------------------------------------------- -void TerrainMesh::createVertexBuffer() { - using namespace Ogre; - - size_t vw = mWidth; - if ( mUseSkirts ) vw += 2; - - mVertexes = new VertexData(); - mVertexes->vertexStart = 0; - mVertexes->vertexCount = vw*vw;// VERTEX_WIDTH; - - VertexDeclaration* vertexDecl = mVertexes->vertexDeclaration; - size_t currOffset = 0; - - vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_POSITION); - currOffset += VertexElement::getTypeSize(VET_FLOAT3); - - vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_NORMAL); - currOffset += VertexElement::getTypeSize(VET_FLOAT3); - - - vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); - currOffset += VertexElement::getTypeSize(VET_FLOAT2); - - if ( g_heightMap->isTextureFadingEnabled() ) { - vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 1); - currOffset += VertexElement::getTypeSize(VET_FLOAT2); - } - - mMainBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( - vertexDecl->getVertexSize(0), // size of one whole vertex - mVertexes->vertexCount, // number of vertices - HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage - false); // no shadow buffer - - mVertexes->vertexBufferBinding->setBinding(MAIN_BINDING, mMainBuffer); //bind the data - - if ( g_heightMap->isMorphingEnabled() ) - vertexDecl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS); - - -} - -Ogre::HardwareVertexBufferSharedPtr TerrainMesh::createDeltaBuffer( ) { - size_t vw = mWidth; - if ( mUseSkirts ) vw += 2; - - const size_t totalVerts = (vw * vw); - return Ogre::HardwareBufferManager::getSingleton().createVertexBuffer( - Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT1), - totalVerts, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, - false); //no shadow buff - -} - - - - -//---------------------------------------------- -#define SET_DELTA_AT(x, y, v) \ -if ( mUseSkirts ) pDeltas[( y + 1)*vw+ x + 1] = v; \ -else pDeltas[( y)*vw+ x] = v; -void TerrainMesh::calculateDeltaValues() { - - using namespace Ogre; - size_t vw = mWidth; - if ( mUseSkirts ) vw += 2; - - //must be using morphing to use this function - assert(g_heightMap->isMorphingEnabled()); - - const size_t step = 2; - - // Create a set of delta values - mDeltaBuffer = createDeltaBuffer(); - float* pDeltas = static_cast(mDeltaBuffer->lock(HardwareBuffer::HBL_DISCARD)); - memset(pDeltas, 0, (vw)*(vw) * sizeof(float)); - - return; - - bool flag=false; - for ( size_t y = 0; y < mWidth-step; y += step ) { - for ( size_t x = 0; x < mWidth-step; x += step ) { - //create the diffrence between the full vertex if the vertex wasn't their - - float bottom_left = getVertexHeight(x,y); - float bottom_right = getVertexHeight(x+step,y); - - float top_left = getVertexHeight(x,y+step); - float top_right = getVertexHeight(x+step,y+step); - - //const int vw = mWidth+2; - SET_DELTA_AT(x, y+1, (bottom_left+top_left)/2 - getVertexHeight(x, y+1)) //left - SET_DELTA_AT(x+2, y+1, (bottom_right+top_right)/2 - getVertexHeight(x+2, y+1)) //right - - SET_DELTA_AT(x+1, y+2, (top_right+top_left)/2 - getVertexHeight(x+1, y+2)) //top - SET_DELTA_AT(x+1, y, (bottom_right+bottom_left)/2 - getVertexHeight(x+1, y)) //bottom - - //this might not be correct - if ( !flag ) - SET_DELTA_AT(x+1, y+1, (bottom_left+top_right)/2 - getVertexHeight(x+1, y+1)) //center - else - SET_DELTA_AT(x+1, y+1, (bottom_right+top_left)/2 - getVertexHeight(x+1, y+1)) //center - - flag = !flag; - } - flag = !flag; //flip tries for next row - } - - mDeltaBuffer->unlock(); - mVertexes->vertexBufferBinding->setBinding(DELTA_BINDING,mDeltaBuffer); - -} -#undef SET_DELTA_AT - -//---------------------------------------------- -void TerrainMesh::calculateIndexValues() { - using namespace Ogre; - - - - size_t vw = mWidth-1; - if ( mUseSkirts ) vw += 2; - - const size_t indexCount = (vw)*(vw)*6; - - //need to manage allocation if not null - assert(mIndices==0); - - mIndices = new IndexData(); - mIndices->indexCount = indexCount; - mIndices->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( - HardwareIndexBuffer::IT_16BIT, - indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); - - unsigned short* indices = static_cast(mIndices->indexBuffer->lock(0, - mIndices->indexBuffer->getSizeInBytes(), - HardwareBuffer::HBL_DISCARD)); - - bool flag = false; - Ogre::uint indNum = 0; - for ( Ogre::uint y = 0; y < (vw); y+=1 ) { - for ( Ogre::uint x = 0; x < (vw); x+=1 ) { - - const int line1 = y * (vw+1) + x; - const int line2 = (y + 1) * (vw+1) + x; - - if ( flag ) { - *indices++ = line1; - *indices++ = line2; - *indices++ = line1 + 1; - - *indices++ = line1 + 1; - *indices++ = line2; - *indices++ = line2 + 1; - } else { - *indices++ = line1; - *indices++ = line2; - *indices++ = line2 + 1; - - *indices++ = line1; - *indices++ = line2 + 1; - *indices++ = line1 + 1; - } - flag = !flag; //flip tris for next time - - indNum+=6; - } - flag = !flag; //flip tries for next row - } - assert(indNum==indexCount); - mIndices->indexBuffer->unlock(); - //return mIndices; -}