mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Textures are now blended between cells and the texture blending functions are now more abstract
This commit is contained in:
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…
x
Reference in New Issue
Block a user