mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 20:19:57 +00:00
- preparing to rewrite the landscape gen phase
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@116 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
401bd35e02
commit
c18a1ebd05
7 changed files with 321 additions and 152 deletions
|
@ -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);
|
||||
|
|
|
@ -14,13 +14,13 @@ 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 ) {
|
||||
// Recreate the mesh if the view distance has increased
|
||||
if ( vd > mMeshDistance )
|
||||
{
|
||||
destroyMaterial();
|
||||
destroyMesh();
|
||||
createMaterial();
|
||||
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
|
|
@ -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<int>(mMWLand.getMaxX(), max);
|
||||
max = std::max<int>(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<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();
|
||||
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<int>& 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
|
||||
// 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<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 texX = 0; texX < LAND_LTEX_WIDTH+2; texX++ )
|
||||
{
|
||||
|
@ -269,25 +294,30 @@ 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<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);
|
||||
|
||||
//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
|
||||
{
|
||||
// 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;
|
||||
|
||||
// Get the data from the ESM
|
||||
if ( mMWLand.hasData(x + blockX, y + blockY) )
|
||||
{
|
||||
source = mMWLand.getSource(x + blockX, y + blockY);
|
||||
|
@ -298,18 +328,24 @@ private:
|
|||
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
|
||||
// Convert .tga to .dds
|
||||
// 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?
|
||||
//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;
|
||||
|
||||
// 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: Now, I KNOW this isn't needed :)
|
||||
// See if we have used anything at all. FIXME: This isn't needed
|
||||
// as a separate loop
|
||||
int sum = 0;
|
||||
for ( std::vector<int>::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<int>& 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");
|
||||
|
|
|
@ -3,23 +3,18 @@ class TextureSplatter
|
|||
public:
|
||||
inline TextureSplatter(const std::vector<int>& ltex,
|
||||
int texSize,
|
||||
int ltexsize,
|
||||
int border) :
|
||||
mLTEX(ltex),
|
||||
int ltexsize)
|
||||
: 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);
|
||||
}
|
||||
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<int>& mLTEX;
|
||||
const int mTexSize;
|
||||
const int mLTEXSize;
|
||||
const int mBorder;
|
||||
int mSizeDiff;
|
||||
};
|
||||
|
||||
|
@ -93,7 +88,7 @@ public:
|
|||
/**
|
||||
* 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 border,
|
||||
float scaleDiv,
|
||||
|
@ -101,22 +96,188 @@ 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);
|
||||
|
||||
// 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);
|
||||
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<int> textures;
|
||||
for ( int y1 = 0; y1 < ltexWidth; y1++ ) {
|
||||
for ( int x1 = 0; x1 < ltexWidth; x1++ ) {
|
||||
|
@ -126,7 +287,6 @@ public:
|
|||
|
||||
for ( std::set<int>::iterator itr = textures.begin(); itr != textures.end(); ++itr )
|
||||
{
|
||||
|
||||
int tid = *itr;
|
||||
|
||||
const std::string tn(mTexturePaths[tid]);
|
||||
|
@ -161,7 +321,7 @@ public:
|
|||
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<int> 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;
|
||||
|
|
Loading…
Reference in a new issue