Textures are now blended between cells and the texture blending functions are now more abstract

actorid
Jacob Essex 13 years ago
parent 637302fc87
commit cd0df082df

@ -46,15 +46,17 @@ namespace MWRender
Ogre::Terrain::ImportData terrainData;
terrainData.inputBias = 0;
terrainData.inputFloat = store->land->landData->heights;
terrainData.inputFloat = store->land[1][1]->landData->heights;
std::map<uint16_t, int> indexes;
initTerrainTextures(&terrainData, store, indexes);
initTerrainTextures(&terrainData, store, 0, 0,
ESM::Land::LAND_TEXTURE_SIZE, indexes);
mTerrainGroup->defineTerrain(x, y, &terrainData);
mTerrainGroup->loadTerrain(x, y, true);
Ogre::Terrain* terrain = mTerrainGroup->getTerrain(x,y);
initTerrainBlendMaps(terrain, store, indexes);
initTerrainBlendMaps(terrain, store, 0, 0,
ESM::Land::LAND_TEXTURE_SIZE, indexes);
}
void TerrainManager::cellRemoved(MWWorld::Ptr::CellStore *store)
@ -65,20 +67,29 @@ namespace MWRender
void TerrainManager::initTerrainTextures(Ogre::Terrain::ImportData* terrainData,
MWWorld::Ptr::CellStore* store,
int fromX, int fromY, int size,
std::map<uint16_t, int>& indexes)
{
assert(store != NULL && "store must be a valid pointer");
assert(terrainData != NULL && "Must have valid terrain data");
assert(fromX >= 0 && fromY >= 0 &&
"Can't get a terrain texture on terrain outside the current cell");
assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE &&
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
"Can't get a terrain texture on terrain outside the current cell");
//have a base texture for now, but this is probably not needed on most cells
terrainData->layerList.resize(1);
terrainData->layerList[0].worldSize = 256;
terrainData->layerList[0].textureNames.push_back("textures\\_land_default.dds");
terrainData->layerList[0].textureNames.push_back("textures\\_land_default.dds");
const uint16_t* const textures = store->land->landData->textures;
for ( int y = 0; y < ESM::Land::LAND_TEXTURE_SIZE; y++ )
for ( int y = fromY - 1; y < fromY + size + 1; y++ )
{
for ( int x = 0; x < ESM::Land::LAND_TEXTURE_SIZE; x++ )
for ( int x = fromX - 1; x < fromX + size + 1; x++ )
{
const uint16_t ltexIndex = textures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
const uint16_t ltexIndex = getLtexIndexAt(store, x, y);
//this is the base texture, so we can ignore this at present
if ( ltexIndex == 0 )
{
continue;
@ -89,7 +100,7 @@ namespace MWRender
if ( it == indexes.end() )
{
//NB: All vtex ids are +1 compared to the ltex ids
assert((int)ltexIndex - 1 > 0 &&
assert((int)ltexIndex >= 0 &&
store->landTextures->ltex.size() > (size_t)ltexIndex - 1 &&
"LAND.VTEX must be within the bounds of the LTEX array");
@ -116,11 +127,23 @@ namespace MWRender
void TerrainManager::initTerrainBlendMaps(Ogre::Terrain* terrain,
MWWorld::Ptr::CellStore* store,
int fromX, int fromY, int size,
const std::map<uint16_t, int>& indexes)
{
assert(store != NULL && "store must be a valid pointer");
assert(terrain != NULL && "Must have valid terrain");
assert(fromX >= 0 && fromY >= 0 &&
"Can't get a terrain texture on terrain outside the current cell");
assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE &&
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
"Can't get a terrain texture on terrain outside the current cell");
//size must be a power of 2 as we do divisions with a power of 2 number
//that need to result in an integer for correct splatting
assert( (size & (size - 1)) == 0 && "Size must be a power of 2");
const int blendSize = terrain->getLayerBlendMapSize();
const int blendDist = TERRAIN_SHADE_DISTANCE *
(blendSize / ESM::Land::LAND_TEXTURE_SIZE);
const int blendDist = TERRAIN_SHADE_DISTANCE * (blendSize / size);
//zero out every map
std::map<uint16_t, int>::const_iterator iter;
@ -132,21 +155,24 @@ namespace MWRender
}
//covert the ltex data into a set of blend maps
const uint16_t* const textures = store->land->landData->textures;
for ( int texY = 0; texY < ESM::Land::LAND_TEXTURE_SIZE; texY++ )
for ( int texY = fromY - 1; texY < fromY + size + 1; texY++ )
{
for ( int texX = 0; texX < ESM::Land::LAND_TEXTURE_SIZE; texX++ )
for ( int texX = fromY - 1; texX < fromY + size + 1; texX++ )
{
const uint16_t ltexIndex = textures[texY * ESM::Land::LAND_TEXTURE_SIZE + texX];
const uint16_t ltexIndex = getLtexIndexAt(store, texX, texY);
//this is the ground texture, which is currently the base texture
//so don't alter the splatting map
if ( ltexIndex == 0 ){
continue;
}
const int layerIndex = indexes.find(ltexIndex)->second;
float* const pBlend = terrain->getLayerBlendMap(layerIndex)
->getBlendPointer();
const int splatSize = blendSize / ESM::Land::LAND_TEXTURE_SIZE;
const int splatSize = blendSize / size;
//setup the bounds for the shading of this texture splat
const int startX = std::max(0, texX*splatSize - blendDist);
@ -209,4 +235,51 @@ namespace MWRender
}
int TerrainManager::getLtexIndexAt(MWWorld::Ptr::CellStore* store,
int x, int y)
{
//check texture index falls within the 9 cell bounds
//as this function can't cope with anything above that
assert(x >= -ESM::Land::LAND_TEXTURE_SIZE &&
y >= -ESM::Land::LAND_TEXTURE_SIZE &&
"Trying to get land textures that are out of bounds");
assert(x < 2*ESM::Land::LAND_TEXTURE_SIZE &&
y < 2*ESM::Land::LAND_TEXTURE_SIZE &&
"Trying to get land textures that are out of bounds");
assert(store != NULL && "Store pointer must be valid");
//default center cell is indexed at (1,1)
int cellX = 1;
int cellY = 1;
if ( x < 0 )
{
cellX--;
x += ESM::Land::LAND_TEXTURE_SIZE;
}
else if ( x >= ESM::Land::LAND_TEXTURE_SIZE )
{
cellX++;
x -= ESM::Land::LAND_TEXTURE_SIZE;
}
if ( y < 0 )
{
cellY--;
y += ESM::Land::LAND_TEXTURE_SIZE;
}
else if ( y >= ESM::Land::LAND_TEXTURE_SIZE )
{
cellY++;
y -= ESM::Land::LAND_TEXTURE_SIZE;
}
return store->land[cellX][cellY]
->landData
->textures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
}
}

@ -35,23 +35,49 @@ namespace MWRender{
static const float TERRAIN_SHADE_DISTANCE = 0.5;
/**
* Setups up the list of textures for the cell
* Setups up the list of textures for part of a cell, using indexes as
* an output to create a mapping of MW LtexIndex to the relevant terrain
* layer
*
* @param terrainData the terrain data to setup the textures for
* @param store the cell store for the given terrain cell
* @param fromX the ltex index in the current cell to start making the texture from
* @param fromY the ltex index in the current cell to start making the texture from
* @param size the size (number of splats) to get
* @param indexes a mapping of ltex index to the terrain texture layer that
* can be used by initTerrainBlendMaps
*/
void initTerrainTextures(Ogre::Terrain::ImportData* terrainData,
MWWorld::Ptr::CellStore* store,
int fromX, int fromY, int size,
std::map<uint16_t, int>& indexes);
/**
* Creates the blend (splatting maps) for the given terrain from the ltex data.
*
* @param terrain the terrain object for the current cell
* @param store the cell store for the given terrain cell
* @param fromX the ltex index in the current cell to start making the texture from
* @param fromY the ltex index in the current cell to start making the texture from
* @param size the size (number of splats) to get
* @param indexes the mapping of ltex to blend map produced by initTerrainTextures
*/
void initTerrainBlendMaps(Ogre::Terrain* terrain,
MWWorld::Ptr::CellStore* store,
int fromX, int fromY, int size,
const std::map<uint16_t, int>& indexes);
/**
* Gets a LTEX index at the given point, assuming the current cell
* starts at (0,0). This supports getting values from the surrounding
* cells so negative x, y is acceptable
*
* @param store the cell store for the current cell
* @param x, y the splat position of the ltex index to get relative to the
* first splat of the current cell
*/
int getLtexIndexAt(MWWorld::Ptr::CellStore* store, int x, int y);
};
}

@ -96,8 +96,8 @@ namespace ESMS
State_Unloaded, State_Preloaded, State_Loaded
};
CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded),
land(NULL) {}
CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded)
{}
const ESM::Cell *cell;
State mState;
@ -125,7 +125,7 @@ namespace ESMS
CellRefList<Static, D> statics;
CellRefList<Weapon, D> weapons;
const Land* land;
const Land* land[3][3];
const LTexList* landTextures;
void load (const ESMStore &store, ESMReader &esm)
@ -141,7 +141,16 @@ namespace ESMS
if ( ! (cell->data.flags & ESM::Cell::Interior) )
{
loadTerrain(cell->data.gridX, cell->data.gridY, store, esm);
for ( size_t x = 0; x < 3; x++ )
{
for ( size_t y = 0; y < 3; y++ )
{
land[x][y] = loadTerrain(cell->data.gridX + x - 1,
cell->data.gridY + y - 1,
store,
esm);
}
}
landTextures = &store.landTexts;
}
@ -190,7 +199,7 @@ namespace ESMS
private:
void loadTerrain(int X, int Y, const ESMStore &store, ESMReader &esm)
Land* loadTerrain(int X, int Y, const ESMStore &store, ESMReader &esm)
{
// load terrain
Land *land = store.lands.search(X, Y);
@ -199,18 +208,13 @@ namespace ESMS
land->loadData(esm);
}
this->land = land;
return land;
}
void unloadTerrain(int X, int Y, const ESMStore &store) {
Land *land = store.lands.search(X,Y);
// unload terrain
if (land != NULL)
{
land->unloadData();
}
this->land = NULL;
assert (false &&
"This function is not implemented due to the fact that we now store overlapping land blocks so" &&
"we cannot be sure that the land segment is not being used by another CellStore");
}
template<class Functor, class List>

Loading…
Cancel
Save