From c18a1ebd05e6ce7c862c3e49a27624028f102f23 Mon Sep 17 00:00:00 2001 From: nkorslund Date: Mon, 18 May 2009 11:32:26 +0000 Subject: [PATCH] - preparing to rewrite the landscape gen phase git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@116 ea6a568a-9f4f-0410-981a-c910a81bb256 --- monster/util/freelist.d | 11 -- terrain/cpp_baseland.cpp | 25 ++-- terrain/cpp_framelistener.cpp | 28 +---- terrain/cpp_generator.cpp | 149 ++++++++++++++-------- terrain/cpp_materialgen.cpp | 224 +++++++++++++++++++++++++++++----- terrain/cpp_terrain.cpp | 15 ++- terrain/cpp_terrainmesh.cpp | 21 ++-- 7 files changed, 321 insertions(+), 152 deletions(-) diff --git a/monster/util/freelist.d b/monster/util/freelist.d index 0037cb402..df6f2fe98 100644 --- a/monster/util/freelist.d +++ b/monster/util/freelist.d @@ -19,7 +19,6 @@ 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/ . - */ module monster.util.freelist; @@ -183,16 +182,6 @@ struct Buffers BufferList!(256) b256; BufferList!(768) b768; - /* - static this() - { - writefln("64: ints=%s bytes=%s", b64.ints, b64.bytes); - writefln("128: ints=%s bytes=%s", b128.ints, b128.bytes); - writefln("256: ints=%s bytes=%s", b256.ints, b256.bytes); - writefln("768: ints=%s bytes=%s", b768.ints, b768.bytes); - } - */ - int[] getInt(uint size) { if(size <= b64.ints) return b64.getInt(size); diff --git a/terrain/cpp_baseland.cpp b/terrain/cpp_baseland.cpp index cc796f006..c7925a875 100644 --- a/terrain/cpp_baseland.cpp +++ b/terrain/cpp_baseland.cpp @@ -14,18 +14,18 @@ public: destroyMesh(); } - /** - * @brief repositions the mesh, and ensures that it is the right size - */ + // Repositions the mesh based on camera location void update() { Ogre::Real vd = mCamera->getFarClipDistance(); - if ( vd > mMeshDistance ) { - destroyMaterial(); - destroyMesh(); - createMaterial(); - createMesh(); - } + // Recreate the mesh if the view distance has increased + if ( vd > mMeshDistance ) + { + destroyMaterial(); + destroyMesh(); + createMaterial(); + createMesh(); + } Ogre::Vector3 p = mCamera->getDerivedPosition(); p.x -= ((int)p.x % 8192); @@ -49,7 +49,6 @@ private: mMeshDistance = vd; - mObject->position(-vd,-2048, vd); mObject->textureCoord(0, 1); @@ -66,7 +65,6 @@ private: mObject->end(); - mNode = mTerrainSceneNode->createChildSceneNode(); mNode->attachObject(mObject); } @@ -78,6 +76,11 @@ private: 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(); diff --git a/terrain/cpp_framelistener.cpp b/terrain/cpp_framelistener.cpp index 45920519c..b55e66488 100644 --- a/terrain/cpp_framelistener.cpp +++ b/terrain/cpp_framelistener.cpp @@ -1,9 +1,6 @@ class TerrainFrameListener : public FrameListener { protected: - /** - * Updates the quad tree - */ bool frameEnded(const FrameEvent& evt) { g_rootQuad->update(evt.timeSinceLastFrame); @@ -25,32 +22,11 @@ public: g_heightMap = new HeightMap(node); g_heightMap->load(TERRAIN_OUTPUT); - //fix settings + // Fix settings g_heightMap->setMorphingEnabled(false); g_heightMap->setTextureFadingEnabled(false); - //create the quad node + // Create the root quad g_rootQuad = new Quad(Quad::QL_ROOT, 0); } - - /* KILLME - void drawLine(std::string name, Ogre::Vector3 start, Ogre::Vector3 end) - { - Ogre::ManualObject* mo = mSceneMgr->createManualObject( name); - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name+"node"); - - Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create( name+"Material","debugger"); - mat->setReceiveShadows(false); - mat->getTechnique(0)->setLightingEnabled(true); - mat->getTechnique(0)->getPass(0)->setDiffuse(0,0,1,0); - mat->getTechnique(0)->getPass(0)->setAmbient(0,0,1); - mat->getTechnique(0)->getPass(0)->setSelfIllumination(0,0,1); - - mo->begin(name+"Material", Ogre::RenderOperation::OT_LINE_LIST); - mo->position(start); - mo->position(end); - mo->end(); - node->attachObject(mo); - } - */ }; diff --git a/terrain/cpp_generator.cpp b/terrain/cpp_generator.cpp index 107b72e2c..2bf1cbf8b 100644 --- a/terrain/cpp_generator.cpp +++ b/terrain/cpp_generator.cpp @@ -1,6 +1,6 @@ /* OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2009 Jacob Essex + Copyright (C) 2009 Jacob Essex, Nicolay Korslund WWW: http://openmw.sourceforge.net/ This file (cpp_generator.cpp) is part of the OpenMW package. @@ -26,7 +26,9 @@ public: Generator(const std::string& baseFileName) : mBaseFileName(baseFileName) { +#if GEN_LANDDATA mDataO.open(std::string(baseFileName+".data").c_str(), std::ios::binary); +#endif } inline void addLandData(RecordPtr record, const std::string& source) @@ -37,7 +39,7 @@ public: void beginGeneration() { - //maxiumum distance form 0, 0 in any direction + // Find the maxiumum distance from (0,0) in any direction int max = 0; max = std::max(mMWLand.getMaxX(), max); max = std::max(mMWLand.getMaxY(), max); @@ -61,13 +63,14 @@ public: //Keep deviding the root side length by 2 (thereby simulating a //split) until we reach the width of the base cell (or the - //smallest quad) + //smallest quad). TODO: We should make sure that the right number + //of levels are actually generated automatically, of course. for (long i = mIndex.getRootSideLength(); i > 8192; i/=2 ) maxDepth++; mIndex.setMaxDepth(maxDepth); } - void generateLODLevel(int level, bool createTexture, int textureSize) + void generateLODLevel(int level, int textureSize) { std::cout << "Generating Level " << level << "\n"; @@ -80,26 +83,33 @@ public: // FIXME: Should probably use another name than 'level' here level = pow((float)2, level); //gap between verts that we want + // Use this instead + assert(level == 1 << initialLevel); + const int halfLevel = level/2; assert(halfLevel > 0 ); - // FIXME. Just search for all pow() calls, really + // FIXME. Search for all pow() calls and fix them int cellDist = pow((float)2, mIndex.getMaxDepth()); // Temporary storage QuadData qd; +#if GEN_LANDDATA qd.setVertexSeperation(128*halfLevel); //dist between two verts - std::vector& gh = qd.getHeightsRef(); //ref to the data storage in the quad + std::vector& gh = qd.getHeightsRef(); //ref to the data + //storage in the quad std::vector& gn = qd.getNormalsRef(); gh.resize(LAND_NUM_VERTS); //allocate memory for mesh functions gn.resize(LAND_NUM_VERTS*3); +#endif - //the 16*16 array used for holding the LTEX records (what texure is splatted where) + //the 16*16 array used for holding the LTEX records (what texure + //is splatted where) std::vector& gl = qd.getTextureIndexRef(); gl.resize((LAND_LTEX_WIDTH+2)*(LAND_LTEX_WIDTH+2)); - const std::string stringLevel(Ogre::StringConverter::toString(level)); //cache this + const std::string stringLevel(Ogre::StringConverter::toString(level)); const std::string defaultTexture(stringLevel + "_default.png"); bool hasUsedDefault = false; @@ -107,21 +117,22 @@ public: for( int y = -(cellDist/2); y < (cellDist/2); y+=halfLevel ) for( int x = -(cellDist/2); x < (cellDist/2); x+=halfLevel ) { - qd.setParentTexture(""); bool usingDefaultTexture = false; if ( initialLevel == 1 ) + // For level one (up close), there's no need to generate + // any textures, as we can use the textures from the BSAs + // directly. generateLTEXData(x, y, gl); - else if ( createTexture ) + else { - //this is the name of the file that OGRE will - //look for - std::string name = stringLevel + "_" + + // Texture file name + std::string name = stringLevel + "_" + Ogre::StringConverter::toString(x) + "_" + Ogre::StringConverter::toString(y) + ".png"; - //where as the arg1 here is the file name to save it. + // Generate the texture bool hasGen = generateTexture(std::string(TEXTURE_OUTPUT) + name, textureSize, x, y, halfLevel); if ( hasGen ) qd.setTexture(name); @@ -133,10 +144,14 @@ public: } } - //calculate parent texture + // Calculate parent texture if ( initialLevel != mIndex.getMaxDepth() ) { + // FIXME: This can definitely be improved, although it + // doesn't matter performance wise + //calcualte the level one higher + // FIXME: pow() again... int higherLevel = pow((float)2, (initialLevel+1)); int highHalfLevel = higherLevel/2; @@ -144,7 +159,6 @@ public: if ( (higherX-halfLevel) % highHalfLevel == 0 ) higherX -= halfLevel; - int higherY = y; if ( (higherY-halfLevel) % highHalfLevel == 0 ) higherY -= halfLevel; @@ -153,7 +167,7 @@ public: Ogre::StringConverter::toString(higherX) + "_" + Ogre::StringConverter::toString(higherY) + ".png"; - //check file exists without needing boost filesystenm libs + //check file exists without needing boost filesystem libs FILE* fp = fopen((std::string(TEXTURE_OUTPUT) + higherName).c_str(), "r"); if ( fp ) { @@ -163,6 +177,8 @@ public: else qd.setParentTexture(""); } + +#if GEN_LANDDATA generateMesh(gh, gn, x, y, halfLevel ); bool isEmptyQuad = true; @@ -187,6 +203,8 @@ public: mDataO.tellp()); boost::archive::binary_oarchive oa(mDataO); //using boost fs to write the quad oa << qd; +#endif + } //check if we have used a default texture @@ -201,20 +219,27 @@ public: void endGeneration() { // FIXME: Just write one file? - std::ofstream ofi(std::string(mBaseFileName + ".index").c_str(), std::ios::binary); - std::ofstream ofp(std::string(mBaseFileName + ".palette").c_str(), std::ios::binary); - boost::archive::binary_oarchive oai(ofi); - boost::archive::binary_oarchive oap(ofp); - oai << mIndex; - oap << mPalette; - +#if GEN_LANDDATA mDataO.close(); + std::ofstream ofi(std::string(mBaseFileName + ".index").c_str(), std::ios::binary); + boost::archive::binary_oarchive oai(ofi); + oai << mIndex; +#endif + + std::ofstream ofp(std::string(mBaseFileName + ".palette").c_str(), std::ios::binary); + boost::archive::binary_oarchive oap(ofp); + oap << mPalette; } private: + // Generate texture data for level 1. void generateLTEXData(int x, int y, std::vector& index) { + // All this does is to loop through all the 16x16 'land grid + // points' in the cell (plus the outer border of grid points from + // the surrounding cells) and store the texture names in the + // index. for ( int texY = 0; texY < LAND_LTEX_WIDTH+2; texY++ ) for ( int texX = 0; texX < LAND_LTEX_WIDTH+2; texX++ ) { @@ -269,47 +294,58 @@ private: } } + // Create a cache texture. bool generateTexture(const std::string& name, int size, int blockX, int blockY, int halfLevel) { int width = size/(halfLevel*LAND_LTEX_WIDTH); assert(width>=1); - std::vector ltex; //prealloc, as we know exactly what size it needs to be + // Preallocate a buffer of texture indices + std::vector ltex; ltex.resize(halfLevel*LAND_LTEX_WIDTH*halfLevel*LAND_LTEX_WIDTH, 0); - //for each cell + // This loop collection is just to gather the texture indices for + // this quad. All texture paths are inserted into the for ( int y = 0; y < halfLevel; y++ ) for ( int x = 0; x < halfLevel; x++ ) - //for each texture in the cell - for ( int texY = 0; texY < LAND_LTEX_WIDTH; texY++ ) - for ( int texX = 0; texX < LAND_LTEX_WIDTH; texX++ ) - { - std::string source; - short texID = 0; + { + // And loop over all 16x16 textures in each cell + for ( int texY = 0; texY < LAND_LTEX_WIDTH; texY++ ) + for ( int texX = 0; texX < LAND_LTEX_WIDTH; texX++ ) + { + std::string source; + short texID = 0; - if ( mMWLand.hasData(x + blockX, y + blockY) ) - { - source = mMWLand.getSource(x + blockX, y + blockY); - texID = mMWLand.getLTEXIndex(x + blockX, y + blockY, texX, texY); - } + // Get the data from the ESM + if ( mMWLand.hasData(x + blockX, y + blockY) ) + { + source = mMWLand.getSource(x + blockX, y + blockY); + texID = mMWLand.getLTEXIndex(x + blockX, y + blockY, texX, texY); + } - std::string texturePath = "_land_default.dds"; - if ( texID != 0 && mMWLand.hasLTEXRecord(source,--texID) ) - texturePath = mMWLand.getLTEXRecord(source,texID); + std::string texturePath = "_land_default.dds"; + if ( texID != 0 && mMWLand.hasLTEXRecord(source,--texID) ) + texturePath = mMWLand.getLTEXRecord(source,texID); - //textures given as tga, when they are a dds. I hate that "feature" - //FIXME: ditto earlier comment - size_t d = texturePath.find_last_of(".") + 1; - texturePath = texturePath.substr(0, d) + "dds"; - //FIXME: BTW, didn't we make the BSA reader case insensitive? - std::transform(texturePath.begin(), texturePath.end(), texturePath.begin(), tolower); - const int index = (y*LAND_LTEX_WIDTH+texY)*halfLevel*LAND_LTEX_WIDTH + x*LAND_LTEX_WIDTH+texX; - ltex[index] = mPalette.getOrAddIndex(texturePath); - } + // Convert .tga to .dds + // FIXME: ditto earlier comment. + size_t d = texturePath.find_last_of(".") + 1; + texturePath = texturePath.substr(0, d) + "dds"; + //FIXME2: BTW, didn't we make the BSA reader case insensitive? + std::transform(texturePath.begin(), texturePath.end(), texturePath.begin(), tolower); + const int index = (y*LAND_LTEX_WIDTH+texY)*halfLevel*LAND_LTEX_WIDTH + x*LAND_LTEX_WIDTH+texX; - //see if we have used anything at all - // FIXME: Now, I KNOW this isn't needed :) + // FIXME: In any case, we should let mPalette do the + // name conversion. So if the texture is already + // inserted (which will almost always be the case) we + // can avoid costly string operations. + ltex[index] = mPalette.getOrAddIndex(texturePath); + } + } + + // See if we have used anything at all. FIXME: This isn't needed + // as a separate loop int sum = 0; for ( std::vector::iterator i = ltex.begin(); i != ltex.end(); ++i ) sum += *i; @@ -327,6 +363,9 @@ private: // dependent, when it should be a simple computational exercise. But // understand what it actually does, before you change anything. + // This function (and it's sub calls) is where most of the time is + // spent in the gen process, so this is also where we need to + // optimize. void renderTexture(const std::string& outputName, std::vector& ltex, int texSize, int alphaSize) { @@ -339,10 +378,12 @@ private: MaterialGenerator mg; mg.setTexturePaths(mPalette.getPalette()); + // Aaand, this is just halfLevel again, which already is a very + // poor name for the number of cells along the side of the quad. const int scaleDiv = alphaSize/LAND_LTEX_WIDTH; //genetate material/aplahas - Ogre::MaterialPtr mp = mg.getAlphaMat(ltex, alphaSize, 0, scaleDiv,createdResources); + Ogre::MaterialPtr mp = mg.getAlphaMat(ltex, alphaSize, scaleDiv,createdResources); Ogre::TexturePtr tex1 = getRenderedTexture(mp, "RTT_TEX_1",texSize, Ogre::PF_R8G8B8); tex1->getBuffer()->getRenderTarget()->writeContentsToFile(outputName); Ogre::MaterialManager::getSingleton().remove(mp->getHandle()); @@ -359,6 +400,7 @@ private: } } + // Does everything in OGRE Ogre::TexturePtr getRenderedTexture(Ogre::MaterialPtr mp, const std::string& name, int texSize, Ogre::PixelFormat tt) { @@ -393,8 +435,7 @@ private: renderTexture->update(); - //required for some reason? - //Not implementing resulted in a black tex using openGL, Linux, and a nvidia 6150 in 1.4.? + // Call the OGRE renderer. Ogre::Root::getSingleton().renderOneFrame(); Ogre::CompositorManager::getSingleton().removeCompositor(vp, "Rtt_Comp"); diff --git a/terrain/cpp_materialgen.cpp b/terrain/cpp_materialgen.cpp index 3872139a8..6743bbb1a 100644 --- a/terrain/cpp_materialgen.cpp +++ b/terrain/cpp_materialgen.cpp @@ -3,23 +3,18 @@ class TextureSplatter public: inline TextureSplatter(const std::vector& ltex, int texSize, - int ltexsize, - int border) : - mLTEX(ltex), - mTexSize(texSize), //the root of the size of the texture - mLTEXSize(ltexsize), //the root of the ltex array - mBorder(border) { //the size of the border of the ltex - mSizeDiff = texSize/(ltexsize-border*2); - } + int ltexsize) + : mLTEX(ltex), + mTexSize(texSize), //the root of the size of the texture + mLTEXSize(ltexsize) //the root of the ltex array + { mSizeDiff = texSize/ltexsize; } - int getAlphaAtPixel(int x, int y, int tid) { - //offset for border - x += (mBorder*mSizeDiff); - y += (mBorder*mSizeDiff); - - if ( getTextureAtPixel(x,y) == tid ) { + int getAlphaAtPixel(int x, int y, int tid) + { + if ( getTextureAtPixel(x,y) == tid ) return 255; - } else if ( mBorder > 0 ) + /* + else if ( mBorder > 0 ) { //hacky remove fix. perofrmance issues. skips if not ingame gen. float amount = 0; @@ -39,6 +34,7 @@ public: assert(amount>=0&&amount<=1); return amount*255; } + */ return 0; } @@ -54,7 +50,6 @@ private: const std::vector& mLTEX; const int mTexSize; const int mLTEXSize; - const int mBorder; int mSizeDiff; }; @@ -71,8 +66,8 @@ public: * texture. Only used at runtime, not while generating. */ Ogre::MaterialPtr generateSingleTexture - (const std::string& texName, - std::list createdResources) + (const std::string& texName, + std::list createdResources) { const std::string matname("MAT" + Ogre::StringConverter::toString(mCount++)); @@ -93,7 +88,7 @@ public: /** * gets the material for the alpha textures */ - Ogre::MaterialPtr getAlphaMat(std::vector& ltex, + Ogre::MaterialPtr new_getAlphaMat(std::vector& ltex, int size, int border, float scaleDiv, @@ -101,32 +96,91 @@ public: { const std::string materialName("MAT" + Ogre::StringConverter::toString(mCount++)); + // We REALLY need to clean these variables up + + // Number of textures along one side + const int ltexWidth = Ogre::Math::Sqrt(ltex.size()); + + // Only true if border = 0, which I guess I've assumed below + assert(ltexWidth == size); + + // Side for the quad only, not including the border. Used for the + // assert() below only. + const int rootSideLength = ltexWidth-(border*2); + + // Multiply up the number of textures along a side to get the + // resolution of the alpha map. This gives 4*4=16 alpha pixels per + // texture square, or 4*16 = 64 alpha pixels across the entire + // quad. const int sizeDiff = 4; size *= sizeDiff; - const int rootSideLength = Ogre::Math::Sqrt(ltex.size())-(border*2); //used for looping - const int ltexWidth = Ogre::Math::Sqrt(ltex.size()); assert(size%rootSideLength==0); Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton(). create(materialName,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); createdResources.push_back(material); - + // But the default texture in the bottom 'layer', so that we don't + // end up seeing through the landscape. Ogre::Pass* np = material->getTechnique(0)->getPass(0); np->setLightingEnabled(false); + // FIXME: Why 0.1f? np->createTextureUnitState("_land_default.dds")->setTextureScale(0.1f/scaleDiv,0.1f/scaleDiv); - std::set textures; - for ( int y1 = 0; y1 < ltexWidth; y1++ ) { - for ( int x1 = 0; x1 < ltexWidth; x1++ ) { - textures.insert(ltex[(y1)*ltexWidth+x1]); - } - } + // Put all the texture indices in a set + typedef std::set SI; + typedef SI::iterator SI_it; + SI textures; + for( int in = 0; in < ltex.size(); in++ ) + textures.insert(ltex[in]); - for ( std::set::iterator itr = textures.begin(); itr != textures.end(); ++itr ) + // Allocate the buffers + typedef std::vector AlphaBuf; + std::map alphaMap; + + const int bufSize = size*size; + + //TextureSplatter ts(ltex, size, ltexWidth, border); + + // Peform splatting. Loop over each texture square in this quad. + for(int ty=0; ty < size; ty += sizeDiff) + for(int tx=0; tx < size; tx += sizeDiff) + { + // Get the texture index for this square + const int thisInd = ltex[tx + ltexWidth*ty]; + + // Offset for this texture + const int offs = ty*size + tx; + + AlphaBuf &abuf = alphaMap[thisInd]; + + abuf.resize(bufSize); + + // Set alphas to full for this square + for(int y=0; y= abuf.size()) + std::cout << "tx=" << tx << " ty=" << ty + << " x=" << x << " y=" << y + << " offs=" << offs + << " toffs=" << toffs + << " abuf.size()=" << abuf.size() + << "\n"; + assert(toffs < abuf.size()); + abuf[toffs] = 255; + } + + // Get alpha influence from neighbouring cells. + + // FIXME: Rewrite TextureSplatter + } + + // Create passes for each alpha buffer + for ( SI_it itr = textures.begin(); itr != textures.end(); ++itr ) { - int tid = *itr; const std::string tn(mTexturePaths[tid]); @@ -146,7 +200,113 @@ public: Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, // Name of resource group in which the texture should be created Ogre::TEX_TYPE_2D, size,size, //size ofc - 1, 0, //depth, mipmaps + 1,0, //depth, mipmaps + Ogre::PF_A8, //we only need one channel to hold the splatting texture + Ogre::TU_STATIC_WRITE_ONLY //best performace, we shopuldn't need the data again + ); + + createdResources.push_back(texPtr); + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texPtr->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + Ogre::uint8* pDest = static_cast(pixelBox.data); + + AlphaBuf *abuf = &alphaMap[tid]; + for(AlphaBuf::iterator it = abuf->begin(); it != abuf->end(); it++) + *(pDest++) = *it; + + pixelBuffer->unlock(); + + np = material->getTechnique(0)->createPass(); + np->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); + np->setLightingEnabled(false); + np->setDepthFunction(Ogre::CMPF_EQUAL); + + + Ogre::TextureUnitState* tus = np->createTextureUnitState(alphaName); + tus->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); + + tus->setAlphaOperation( Ogre::LBX_BLEND_TEXTURE_ALPHA, + Ogre::LBS_TEXTURE, + Ogre::LBS_TEXTURE); + tus->setColourOperationEx( Ogre::LBX_BLEND_DIFFUSE_ALPHA, + Ogre::LBS_TEXTURE, + Ogre::LBS_TEXTURE); + tus->setIsAlpha(true); + + + tus = np->createTextureUnitState(tn); + tus->setColourOperationEx( Ogre::LBX_BLEND_DIFFUSE_ALPHA, + Ogre::LBS_TEXTURE, + Ogre::LBS_CURRENT); + tus->setTextureScale(0.1f/scaleDiv,0.1f/scaleDiv); + } + + return material; + } + + // The old variant + Ogre::MaterialPtr getAlphaMat(std::vector& ltex, + int size, + float scaleDiv, + std::list& createdResources) + { + const std::string materialName("MAT" + Ogre::StringConverter::toString(mCount++)); + + // Multiply up the number of textures along a side to get the + // resolution of the alpha map. This gives 4*4=16 alpha pixels per + // texture square, or 4*16 = 64 alpha pixels across the entire + // quad. + const int sizeDiff = 4; + size *= sizeDiff; + + // Number of textures along one side + const int ltexWidth = Ogre::Math::Sqrt(ltex.size()); + + assert(size%ltexWidth==0); + + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton(). + create(materialName,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + createdResources.push_back(material); + + // But the default texture in the bottom 'layer', so that we don't + // end up seeing through the landscape. + Ogre::Pass* np = material->getTechnique(0)->getPass(0); + np->setLightingEnabled(false); + np->createTextureUnitState("_land_default.dds")->setTextureScale(0.1f/scaleDiv,0.1f/scaleDiv); + + // Put all the texture indices in a set + std::set textures; + for ( int y1 = 0; y1 < ltexWidth; y1++ ) { + for ( int x1 = 0; x1 < ltexWidth; x1++ ) { + textures.insert(ltex[(y1)*ltexWidth+x1]); + } + } + + for ( std::set::iterator itr = textures.begin(); itr != textures.end(); ++itr ) + { + int tid = *itr; + + const std::string tn(mTexturePaths[tid]); + if ( tn == "_land_default.dds" ) + continue; + + //std::cout << " Generating texture " << tn << "\n"; + + std::string alphaName(materialName + "_A_" + tn); + if ( Ogre::TextureManager::getSingleton().resourceExists(alphaName) ) + OGRE_EXCEPT(0, "ALPHA Already Exists", ""); + + //create alpha map + Ogre::TexturePtr texPtr = Ogre::TextureManager::getSingleton(). + createManual( + alphaName, // Name of texture + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, // Name of resource group in which the texture should be created + Ogre::TEX_TYPE_2D, + size,size, //size ofc + 1,0, //depth, mipmaps Ogre::PF_A8, //we only need one channel to hold the splatting texture Ogre::TU_STATIC_WRITE_ONLY //best performace, we shopuldn't need the data again ); @@ -161,7 +321,7 @@ public: Ogre::uint8* pDest = static_cast(pixelBox.data); memset(pDest,0, sizeof(Ogre::uint8)*size*size); - TextureSplatter ts(ltex, size, ltexWidth, border); + TextureSplatter ts(ltex, size, ltexWidth); for ( int ty = 0; ty < size; ty++ ) { for ( int tx = 0; tx < size; tx++ ) { pDest[ty*size+tx] = ts.getAlphaAtPixel(tx,ty, tid); diff --git a/terrain/cpp_terrain.cpp b/terrain/cpp_terrain.cpp index 6ba14603c..38fff11bc 100644 --- a/terrain/cpp_terrain.cpp +++ b/terrain/cpp_terrain.cpp @@ -43,6 +43,9 @@ const int LAND_NUM_VERTS = LAND_VERT_WIDTH*LAND_VERT_WIDTH; const int LAND_LTEX_WIDTH = 16; const int LAND_NUM_LTEX = LAND_LTEX_WIDTH*LAND_LTEX_WIDTH; +// Can be used to turn of landscape data generation +#define GEN_LANDDATA 1 + // Multiplied with the size of the quad. If these are too close, a // quad might end up splitting/unsplitting continuously, since the // quad size changes when we split. @@ -147,12 +150,12 @@ extern "C" void terr_genData() mhm.beginGeneration(); - mhm.generateLODLevel(6, true, 1024); - mhm.generateLODLevel(5, true, 512); - mhm.generateLODLevel(4, true, 256); - mhm.generateLODLevel(3, true, 256); - mhm.generateLODLevel(2, true, 256); - mhm.generateLODLevel(1, false, 128); + mhm.generateLODLevel(6, 1024); + mhm.generateLODLevel(5, 512); + mhm.generateLODLevel(4, 256); + mhm.generateLODLevel(3, 256); + mhm.generateLODLevel(2, 256); + mhm.generateLODLevel(1, 128); mhm.endGeneration(); } diff --git a/terrain/cpp_terrainmesh.cpp b/terrain/cpp_terrainmesh.cpp index f56bf8548..2d1005ade 100644 --- a/terrain/cpp_terrainmesh.cpp +++ b/terrain/cpp_terrainmesh.cpp @@ -14,7 +14,6 @@ public: Ogre::MovableObject(), mWidth(width), mUseSkirts(skirts), - mBuilt(false), mDepth(depth), mVertexes(0), mIndices(0), @@ -74,14 +73,10 @@ public: if ( g_heightMap->isMorphingEnabled() ) calculateDeltaValues(); - - mBuilt = true; } ~TerrainMesh() { - if ( !mBuilt ) return; - //deleting null values is fine iirc delete mIndices; @@ -97,8 +92,6 @@ public: } # endif - mBuilt = false; - assert(node); node->detachAllObjects(); @@ -323,17 +316,24 @@ private: std::vector ti; + /* ti.resize((size+2)*(size+2), -1); - for ( int y = 0; y < size+2; ++y ){ for ( int x = 0; x < size+2; ++x ){ ti[(y)*(size+2)+(x)] = tref.at((y+yoff)*(indexSize)+(x+xoff)); } } + */ + ti.resize(size*size, -1); + for ( int y = 0; y < size; ++y ){ + for ( int x = 0; x < size; ++x ){ + ti[y*size+x] = tref.at((1+y+yoff)*(indexSize)+(1+x+xoff)); + } + } mMaterial = g_materialGen->getAlphaMat (ti,size, - 1, 1.0f/size, + 1.0f/size, mQuadData->getUsedResourcesRef()); } @@ -712,9 +712,6 @@ else pDeltas[( y)*vw+ x] = v; const int mWidth; const bool mUseSkirts; - ///true if the land has been built - bool mBuilt; - int mDepth; Ogre::MaterialPtr mMaterial;