- preparing to rewrite the landscape gen phase

git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@116 ea6a568a-9f4f-0410-981a-c910a81bb256
actorid
nkorslund 16 years ago
parent 401bd35e02
commit c18a1ebd05

@ -19,7 +19,6 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
version 3 along with this program. If not, see version 3 along with this program. If not, see
http://www.gnu.org/licenses/ . http://www.gnu.org/licenses/ .
*/ */
module monster.util.freelist; module monster.util.freelist;
@ -183,16 +182,6 @@ struct Buffers
BufferList!(256) b256; BufferList!(256) b256;
BufferList!(768) b768; 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) int[] getInt(uint size)
{ {
if(size <= b64.ints) return b64.getInt(size); if(size <= b64.ints) return b64.getInt(size);

@ -14,18 +14,18 @@ public:
destroyMesh(); destroyMesh();
} }
/** // Repositions the mesh based on camera location
* @brief repositions the mesh, and ensures that it is the right size
*/
void update() void update()
{ {
Ogre::Real vd = mCamera->getFarClipDistance(); Ogre::Real vd = mCamera->getFarClipDistance();
if ( vd > mMeshDistance ) { // Recreate the mesh if the view distance has increased
destroyMaterial(); if ( vd > mMeshDistance )
destroyMesh(); {
createMaterial(); destroyMaterial();
createMesh(); destroyMesh();
} createMaterial();
createMesh();
}
Ogre::Vector3 p = mCamera->getDerivedPosition(); Ogre::Vector3 p = mCamera->getDerivedPosition();
p.x -= ((int)p.x % 8192); p.x -= ((int)p.x % 8192);
@ -49,7 +49,6 @@ private:
mMeshDistance = vd; mMeshDistance = vd;
mObject->position(-vd,-2048, vd); mObject->position(-vd,-2048, vd);
mObject->textureCoord(0, 1); mObject->textureCoord(0, 1);
@ -66,7 +65,6 @@ private:
mObject->end(); mObject->end();
mNode = mTerrainSceneNode->createChildSceneNode(); mNode = mTerrainSceneNode->createChildSceneNode();
mNode->attachObject(mObject); mNode->attachObject(mObject);
} }
@ -78,6 +76,11 @@ private:
mNode->getParentSceneNode()->removeAndDestroyChild(mNode->getName()); 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() void createMaterial()
{ {
float vd = mCamera->getFarClipDistance(); float vd = mCamera->getFarClipDistance();

@ -1,9 +1,6 @@
class TerrainFrameListener : public FrameListener class TerrainFrameListener : public FrameListener
{ {
protected: protected:
/**
* Updates the quad tree
*/
bool frameEnded(const FrameEvent& evt) bool frameEnded(const FrameEvent& evt)
{ {
g_rootQuad->update(evt.timeSinceLastFrame); g_rootQuad->update(evt.timeSinceLastFrame);
@ -25,32 +22,11 @@ public:
g_heightMap = new HeightMap(node); g_heightMap = new HeightMap(node);
g_heightMap->load(TERRAIN_OUTPUT); g_heightMap->load(TERRAIN_OUTPUT);
//fix settings // Fix settings
g_heightMap->setMorphingEnabled(false); g_heightMap->setMorphingEnabled(false);
g_heightMap->setTextureFadingEnabled(false); g_heightMap->setTextureFadingEnabled(false);
//create the quad node // Create the root quad
g_rootQuad = new Quad(Quad::QL_ROOT, 0); 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);
}
*/
}; };

@ -1,6 +1,6 @@
/* /*
OpenMW - The completely unofficial reimplementation of Morrowind OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2009 Jacob Essex Copyright (C) 2009 Jacob Essex, Nicolay Korslund
WWW: http://openmw.sourceforge.net/ WWW: http://openmw.sourceforge.net/
This file (cpp_generator.cpp) is part of the OpenMW package. This file (cpp_generator.cpp) is part of the OpenMW package.
@ -26,7 +26,9 @@ public:
Generator(const std::string& baseFileName) : Generator(const std::string& baseFileName) :
mBaseFileName(baseFileName) mBaseFileName(baseFileName)
{ {
#if GEN_LANDDATA
mDataO.open(std::string(baseFileName+".data").c_str(), std::ios::binary); mDataO.open(std::string(baseFileName+".data").c_str(), std::ios::binary);
#endif
} }
inline void addLandData(RecordPtr record, const std::string& source) inline void addLandData(RecordPtr record, const std::string& source)
@ -37,7 +39,7 @@ public:
void beginGeneration() void beginGeneration()
{ {
//maxiumum distance form 0, 0 in any direction // Find the maxiumum distance from (0,0) in any direction
int max = 0; int max = 0;
max = std::max<int>(mMWLand.getMaxX(), max); max = std::max<int>(mMWLand.getMaxX(), max);
max = std::max<int>(mMWLand.getMaxY(), max); max = std::max<int>(mMWLand.getMaxY(), max);
@ -61,13 +63,14 @@ public:
//Keep deviding the root side length by 2 (thereby simulating a //Keep deviding the root side length by 2 (thereby simulating a
//split) until we reach the width of the base cell (or the //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 ) for (long i = mIndex.getRootSideLength(); i > 8192; i/=2 )
maxDepth++; maxDepth++;
mIndex.setMaxDepth(maxDepth); mIndex.setMaxDepth(maxDepth);
} }
void generateLODLevel(int level, bool createTexture, int textureSize) void generateLODLevel(int level, int textureSize)
{ {
std::cout << "Generating Level " << level << "\n"; std::cout << "Generating Level " << level << "\n";
@ -80,26 +83,33 @@ public:
// FIXME: Should probably use another name than 'level' here // FIXME: Should probably use another name than 'level' here
level = pow((float)2, level); //gap between verts that we want level = pow((float)2, level); //gap between verts that we want
// Use this instead
assert(level == 1 << initialLevel);
const int halfLevel = level/2; const int halfLevel = level/2;
assert(halfLevel > 0 ); 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()); int cellDist = pow((float)2, mIndex.getMaxDepth());
// Temporary storage // Temporary storage
QuadData qd; QuadData qd;
#if GEN_LANDDATA
qd.setVertexSeperation(128*halfLevel); //dist between two verts qd.setVertexSeperation(128*halfLevel); //dist between two verts
std::vector<float>& gh = qd.getHeightsRef(); //ref to the data storage in the quad std::vector<float>& gh = qd.getHeightsRef(); //ref to the data
//storage in the quad
std::vector<char>& gn = qd.getNormalsRef(); std::vector<char>& gn = qd.getNormalsRef();
gh.resize(LAND_NUM_VERTS); //allocate memory for mesh functions gh.resize(LAND_NUM_VERTS); //allocate memory for mesh functions
gn.resize(LAND_NUM_VERTS*3); 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<int>& gl = qd.getTextureIndexRef(); std::vector<int>& gl = qd.getTextureIndexRef();
gl.resize((LAND_LTEX_WIDTH+2)*(LAND_LTEX_WIDTH+2)); 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"); const std::string defaultTexture(stringLevel + "_default.png");
bool hasUsedDefault = false; bool hasUsedDefault = false;
@ -107,21 +117,22 @@ public:
for( int y = -(cellDist/2); y < (cellDist/2); y+=halfLevel ) for( int y = -(cellDist/2); y < (cellDist/2); y+=halfLevel )
for( int x = -(cellDist/2); x < (cellDist/2); x+=halfLevel ) for( int x = -(cellDist/2); x < (cellDist/2); x+=halfLevel )
{ {
qd.setParentTexture(""); qd.setParentTexture("");
bool usingDefaultTexture = false; bool usingDefaultTexture = false;
if ( initialLevel == 1 ) 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); generateLTEXData(x, y, gl);
else if ( createTexture ) else
{ {
//this is the name of the file that OGRE will // Texture file name
//look for std::string name = stringLevel + "_" +
std::string name = stringLevel + "_" +
Ogre::StringConverter::toString(x) + "_" + Ogre::StringConverter::toString(x) + "_" +
Ogre::StringConverter::toString(y) + ".png"; 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); bool hasGen = generateTexture(std::string(TEXTURE_OUTPUT) + name, textureSize, x, y, halfLevel);
if ( hasGen ) qd.setTexture(name); if ( hasGen ) qd.setTexture(name);
@ -133,10 +144,14 @@ public:
} }
} }
//calculate parent texture // Calculate parent texture
if ( initialLevel != mIndex.getMaxDepth() ) if ( initialLevel != mIndex.getMaxDepth() )
{ {
// FIXME: This can definitely be improved, although it
// doesn't matter performance wise
//calcualte the level one higher //calcualte the level one higher
// FIXME: pow() again...
int higherLevel = pow((float)2, (initialLevel+1)); int higherLevel = pow((float)2, (initialLevel+1));
int highHalfLevel = higherLevel/2; int highHalfLevel = higherLevel/2;
@ -144,7 +159,6 @@ public:
if ( (higherX-halfLevel) % highHalfLevel == 0 ) if ( (higherX-halfLevel) % highHalfLevel == 0 )
higherX -= halfLevel; higherX -= halfLevel;
int higherY = y; int higherY = y;
if ( (higherY-halfLevel) % highHalfLevel == 0 ) if ( (higherY-halfLevel) % highHalfLevel == 0 )
higherY -= halfLevel; higherY -= halfLevel;
@ -153,7 +167,7 @@ public:
Ogre::StringConverter::toString(higherX) + "_" + Ogre::StringConverter::toString(higherX) + "_" +
Ogre::StringConverter::toString(higherY) + ".png"; 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"); FILE* fp = fopen((std::string(TEXTURE_OUTPUT) + higherName).c_str(), "r");
if ( fp ) if ( fp )
{ {
@ -163,6 +177,8 @@ public:
else else
qd.setParentTexture(""); qd.setParentTexture("");
} }
#if GEN_LANDDATA
generateMesh(gh, gn, x, y, halfLevel ); generateMesh(gh, gn, x, y, halfLevel );
bool isEmptyQuad = true; bool isEmptyQuad = true;
@ -187,6 +203,8 @@ public:
mDataO.tellp()); mDataO.tellp());
boost::archive::binary_oarchive oa(mDataO); //using boost fs to write the quad boost::archive::binary_oarchive oa(mDataO); //using boost fs to write the quad
oa << qd; oa << qd;
#endif
} }
//check if we have used a default texture //check if we have used a default texture
@ -201,20 +219,27 @@ public:
void endGeneration() void endGeneration()
{ {
// FIXME: Just write one file? // FIXME: Just write one file?
#if GEN_LANDDATA
mDataO.close();
std::ofstream ofi(std::string(mBaseFileName + ".index").c_str(), std::ios::binary); 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 oai(ofi);
boost::archive::binary_oarchive oap(ofp);
oai << mIndex; oai << mIndex;
oap << mPalette; #endif
mDataO.close(); std::ofstream ofp(std::string(mBaseFileName + ".palette").c_str(), std::ios::binary);
boost::archive::binary_oarchive oap(ofp);
oap << mPalette;
} }
private: private:
// Generate texture data for level 1.
void generateLTEXData(int x, int y, std::vector<int>& index) void generateLTEXData(int x, int y, std::vector<int>& 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 texY = 0; texY < LAND_LTEX_WIDTH+2; texY++ )
for ( int texX = 0; texX < LAND_LTEX_WIDTH+2; texX++ ) 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, bool generateTexture(const std::string& name, int size,
int blockX, int blockY, int halfLevel) int blockX, int blockY, int halfLevel)
{ {
int width = size/(halfLevel*LAND_LTEX_WIDTH); int width = size/(halfLevel*LAND_LTEX_WIDTH);
assert(width>=1); assert(width>=1);
std::vector<int> ltex; //prealloc, as we know exactly what size it needs to be // Preallocate a buffer of texture indices
std::vector<int> ltex;
ltex.resize(halfLevel*LAND_LTEX_WIDTH*halfLevel*LAND_LTEX_WIDTH, 0); 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 y = 0; y < halfLevel; y++ )
for ( int x = 0; x < halfLevel; x++ ) for ( int x = 0; x < halfLevel; x++ )
//for each texture in the cell {
for ( int texY = 0; texY < LAND_LTEX_WIDTH; texY++ ) // And loop over all 16x16 textures in each cell
for ( int texX = 0; texX < LAND_LTEX_WIDTH; texX++ ) for ( int texY = 0; texY < LAND_LTEX_WIDTH; texY++ )
{ for ( int texX = 0; texX < LAND_LTEX_WIDTH; texX++ )
std::string source; {
short texID = 0; std::string source;
short texID = 0;
if ( mMWLand.hasData(x + blockX, y + blockY) )
{ // Get the data from the ESM
source = mMWLand.getSource(x + blockX, y + blockY); if ( mMWLand.hasData(x + blockX, y + blockY) )
texID = mMWLand.getLTEXIndex(x + blockX, y + blockY, texX, texY); {
} 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) )
//textures given as tga, when they are a dds. I hate that "feature" texturePath = mMWLand.getLTEXRecord(source,texID);
//FIXME: ditto earlier comment
size_t d = texturePath.find_last_of(".") + 1; // Convert .tga to .dds
texturePath = texturePath.substr(0, d) + "dds"; // FIXME: ditto earlier comment.
//FIXME: BTW, didn't we make the BSA reader case insensitive? size_t d = texturePath.find_last_of(".") + 1;
std::transform(texturePath.begin(), texturePath.end(), texturePath.begin(), tolower); texturePath = texturePath.substr(0, d) + "dds";
const int index = (y*LAND_LTEX_WIDTH+texY)*halfLevel*LAND_LTEX_WIDTH + x*LAND_LTEX_WIDTH+texX; //FIXME2: BTW, didn't we make the BSA reader case insensitive?
ltex[index] = mPalette.getOrAddIndex(texturePath); 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;
// 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 // See if we have used anything at all. FIXME: This isn't needed
// FIXME: Now, I KNOW this isn't needed :) // as a separate loop
int sum = 0; int sum = 0;
for ( std::vector<int>::iterator i = ltex.begin(); i != ltex.end(); ++i ) for ( std::vector<int>::iterator i = ltex.begin(); i != ltex.end(); ++i )
sum += *i; sum += *i;
@ -327,6 +363,9 @@ private:
// dependent, when it should be a simple computational exercise. But // dependent, when it should be a simple computational exercise. But
// understand what it actually does, before you change anything. // 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<int>& ltex, void renderTexture(const std::string& outputName, std::vector<int>& ltex,
int texSize, int alphaSize) int texSize, int alphaSize)
{ {
@ -339,10 +378,12 @@ private:
MaterialGenerator mg; MaterialGenerator mg;
mg.setTexturePaths(mPalette.getPalette()); 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; const int scaleDiv = alphaSize/LAND_LTEX_WIDTH;
//genetate material/aplahas //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); Ogre::TexturePtr tex1 = getRenderedTexture(mp, "RTT_TEX_1",texSize, Ogre::PF_R8G8B8);
tex1->getBuffer()->getRenderTarget()->writeContentsToFile(outputName); tex1->getBuffer()->getRenderTarget()->writeContentsToFile(outputName);
Ogre::MaterialManager::getSingleton().remove(mp->getHandle()); 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, Ogre::TexturePtr getRenderedTexture(Ogre::MaterialPtr mp, const std::string& name,
int texSize, Ogre::PixelFormat tt) int texSize, Ogre::PixelFormat tt)
{ {
@ -393,8 +435,7 @@ private:
renderTexture->update(); renderTexture->update();
//required for some reason? // Call the OGRE renderer.
//Not implementing resulted in a black tex using openGL, Linux, and a nvidia 6150 in 1.4.?
Ogre::Root::getSingleton().renderOneFrame(); Ogre::Root::getSingleton().renderOneFrame();
Ogre::CompositorManager::getSingleton().removeCompositor(vp, "Rtt_Comp"); Ogre::CompositorManager::getSingleton().removeCompositor(vp, "Rtt_Comp");

@ -3,23 +3,18 @@ class TextureSplatter
public: public:
inline TextureSplatter(const std::vector<int>& ltex, inline TextureSplatter(const std::vector<int>& ltex,
int texSize, int texSize,
int ltexsize, int ltexsize)
int border) : : mLTEX(ltex),
mLTEX(ltex), mTexSize(texSize), //the root of the size of the texture
mTexSize(texSize), //the root of the size of the texture mLTEXSize(ltexsize) //the root of the ltex array
mLTEXSize(ltexsize), //the root of the ltex array { mSizeDiff = texSize/ltexsize; }
mBorder(border) { //the size of the border of the ltex
mSizeDiff = texSize/(ltexsize-border*2);
}
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; return 255;
} else if ( mBorder > 0 ) /*
else if ( mBorder > 0 )
{ {
//hacky remove fix. perofrmance issues. skips if not ingame gen. //hacky remove fix. perofrmance issues. skips if not ingame gen.
float amount = 0; float amount = 0;
@ -39,6 +34,7 @@ public:
assert(amount>=0&&amount<=1); assert(amount>=0&&amount<=1);
return amount*255; return amount*255;
} }
*/
return 0; return 0;
} }
@ -54,7 +50,6 @@ private:
const std::vector<int>& mLTEX; const std::vector<int>& mLTEX;
const int mTexSize; const int mTexSize;
const int mLTEXSize; const int mLTEXSize;
const int mBorder;
int mSizeDiff; int mSizeDiff;
}; };
@ -71,8 +66,8 @@ public:
* texture. Only used at runtime, not while generating. * texture. Only used at runtime, not while generating.
*/ */
Ogre::MaterialPtr generateSingleTexture Ogre::MaterialPtr generateSingleTexture
(const std::string& texName, (const std::string& texName,
std::list<Ogre::ResourcePtr> createdResources) std::list<Ogre::ResourcePtr> createdResources)
{ {
const std::string matname("MAT" + Ogre::StringConverter::toString(mCount++)); const std::string matname("MAT" + Ogre::StringConverter::toString(mCount++));
@ -93,7 +88,7 @@ public:
/** /**
* gets the material for the alpha textures * gets the material for the alpha textures
*/ */
Ogre::MaterialPtr getAlphaMat(std::vector<int>& ltex, Ogre::MaterialPtr new_getAlphaMat(std::vector<int>& ltex,
int size, int size,
int border, int border,
float scaleDiv, float scaleDiv,
@ -101,22 +96,188 @@ public:
{ {
const std::string materialName("MAT" + Ogre::StringConverter::toString(mCount++)); 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; const int sizeDiff = 4;
size *= sizeDiff; 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); assert(size%rootSideLength==0);
Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton(). Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().
create(materialName,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); create(materialName,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
createdResources.push_back(material); 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);
// Put all the texture indices in a set
typedef std::set<int> SI;
typedef SI::iterator SI_it;
SI textures;
for( int in = 0; in < ltex.size(); in++ )
textures.insert(ltex[in]);
// Allocate the buffers
typedef std::vector<uint8_t> AlphaBuf;
std::map<int,AlphaBuf> 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<sizeDiff; y++)
for(int x=0; x<sizeDiff; x++)
{
int toffs = offs + y*size + x;
if(toffs >= 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]);
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
);
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<Ogre::uint8*>(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<int>& ltex,
int size,
float scaleDiv,
std::list<Ogre::ResourcePtr>& 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); Ogre::Pass* np = material->getTechnique(0)->getPass(0);
np->setLightingEnabled(false); np->setLightingEnabled(false);
np->createTextureUnitState("_land_default.dds")->setTextureScale(0.1f/scaleDiv,0.1f/scaleDiv); np->createTextureUnitState("_land_default.dds")->setTextureScale(0.1f/scaleDiv,0.1f/scaleDiv);
// Put all the texture indices in a set
std::set<int> textures; std::set<int> textures;
for ( int y1 = 0; y1 < ltexWidth; y1++ ) { for ( int y1 = 0; y1 < ltexWidth; y1++ ) {
for ( int x1 = 0; x1 < ltexWidth; x1++ ) { for ( int x1 = 0; x1 < ltexWidth; x1++ ) {
@ -126,7 +287,6 @@ public:
for ( std::set<int>::iterator itr = textures.begin(); itr != textures.end(); ++itr ) for ( std::set<int>::iterator itr = textures.begin(); itr != textures.end(); ++itr )
{ {
int tid = *itr; int tid = *itr;
const std::string tn(mTexturePaths[tid]); const std::string tn(mTexturePaths[tid]);
@ -146,7 +306,7 @@ public:
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, // Name of resource group in which the texture should be created Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, // Name of resource group in which the texture should be created
Ogre::TEX_TYPE_2D, Ogre::TEX_TYPE_2D,
size,size, //size ofc 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::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 Ogre::TU_STATIC_WRITE_ONLY //best performace, we shopuldn't need the data again
); );
@ -161,7 +321,7 @@ public:
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data); Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
memset(pDest,0, sizeof(Ogre::uint8)*size*size); 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 ty = 0; ty < size; ty++ ) {
for ( int tx = 0; tx < size; tx++ ) { for ( int tx = 0; tx < size; tx++ ) {
pDest[ty*size+tx] = ts.getAlphaAtPixel(tx,ty, tid); pDest[ty*size+tx] = ts.getAlphaAtPixel(tx,ty, tid);

@ -43,6 +43,9 @@ const int LAND_NUM_VERTS = LAND_VERT_WIDTH*LAND_VERT_WIDTH;
const int LAND_LTEX_WIDTH = 16; const int LAND_LTEX_WIDTH = 16;
const int LAND_NUM_LTEX = LAND_LTEX_WIDTH*LAND_LTEX_WIDTH; 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 // Multiplied with the size of the quad. If these are too close, a
// quad might end up splitting/unsplitting continuously, since the // quad might end up splitting/unsplitting continuously, since the
// quad size changes when we split. // quad size changes when we split.
@ -147,12 +150,12 @@ extern "C" void terr_genData()
mhm.beginGeneration(); mhm.beginGeneration();
mhm.generateLODLevel(6, true, 1024); mhm.generateLODLevel(6, 1024);
mhm.generateLODLevel(5, true, 512); mhm.generateLODLevel(5, 512);
mhm.generateLODLevel(4, true, 256); mhm.generateLODLevel(4, 256);
mhm.generateLODLevel(3, true, 256); mhm.generateLODLevel(3, 256);
mhm.generateLODLevel(2, true, 256); mhm.generateLODLevel(2, 256);
mhm.generateLODLevel(1, false, 128); mhm.generateLODLevel(1, 128);
mhm.endGeneration(); mhm.endGeneration();
} }

@ -14,7 +14,6 @@ public:
Ogre::MovableObject(), Ogre::MovableObject(),
mWidth(width), mWidth(width),
mUseSkirts(skirts), mUseSkirts(skirts),
mBuilt(false),
mDepth(depth), mDepth(depth),
mVertexes(0), mVertexes(0),
mIndices(0), mIndices(0),
@ -74,14 +73,10 @@ public:
if ( g_heightMap->isMorphingEnabled() ) if ( g_heightMap->isMorphingEnabled() )
calculateDeltaValues(); calculateDeltaValues();
mBuilt = true;
} }
~TerrainMesh() ~TerrainMesh()
{ {
if ( !mBuilt ) return;
//deleting null values is fine iirc //deleting null values is fine iirc
delete mIndices; delete mIndices;
@ -97,8 +92,6 @@ public:
} }
# endif # endif
mBuilt = false;
assert(node); assert(node);
node->detachAllObjects(); node->detachAllObjects();
@ -323,17 +316,24 @@ private:
std::vector<int> ti; std::vector<int> ti;
/*
ti.resize((size+2)*(size+2), -1); ti.resize((size+2)*(size+2), -1);
for ( int y = 0; y < size+2; ++y ){ for ( int y = 0; y < size+2; ++y ){
for ( int x = 0; x < size+2; ++x ){ for ( int x = 0; x < size+2; ++x ){
ti[(y)*(size+2)+(x)] = tref.at((y+yoff)*(indexSize)+(x+xoff)); 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 mMaterial = g_materialGen->getAlphaMat
(ti,size, (ti,size,
1, 1.0f/size, 1.0f/size,
mQuadData->getUsedResourcesRef()); mQuadData->getUsedResourcesRef());
} }
@ -712,9 +712,6 @@ else pDeltas[( y)*vw+ x] = v;
const int mWidth; const int mWidth;
const bool mUseSkirts; const bool mUseSkirts;
///true if the land has been built
bool mBuilt;
int mDepth; int mDepth;
Ogre::MaterialPtr mMaterial; Ogre::MaterialPtr mMaterial;

Loading…
Cancel
Save