From 9cc3af34e5dc8ebd8b90cee9a3e1bd3da48321b0 Mon Sep 17 00:00:00 2001 From: Jacob Essex Date: Tue, 7 Feb 2012 12:41:08 +0000 Subject: [PATCH 1/2] Removed composite maps, fixes to texture sizes and unloading --- apps/openmw/mwrender/terrain.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 70ecdee73d..a468a44069 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -16,7 +16,20 @@ namespace MWRender mTerrainGlobals = OGRE_NEW Ogre::TerrainGlobalOptions(); mTerrainGlobals->setMaxPixelError(8); - mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 1024 : 256); + mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 256 : 1024); + mTerrainGlobals->setLightMapSize(SPLIT_TERRAIN ? 256 : 1024); + mTerrainGlobals->setCompositeMapSize(SPLIT_TERRAIN ? 256 : 1024); + mTerrainGlobals->setDefaultGlobalColourMapSize(256); + + //10 (default) didn't seem to be quite enough + mTerrainGlobals->setSkirtSize(32); + + /* + * Here we are pushing the composite map distance beyond the edge + * of the rendered terrain due to light issues (the lighting differs + * so much that it is very noticable + */ + mTerrainGlobals->setCompositeMapDistance(ESM::Land::REAL_SIZE*4); Ogre::TerrainMaterialGenerator::Profile* const activeProfile = mTerrainGlobals->getDefaultMaterialGenerator() @@ -27,6 +40,7 @@ namespace MWRender matProfile->setLightmapEnabled(false); matProfile->setReceiveDynamicShadowsEnabled(false); + //scale the land size if required mLandSize = ESM::Land::LAND_SIZE; mRealSize = ESM::Land::REAL_SIZE; if ( SPLIT_TERRAIN ) @@ -109,6 +123,8 @@ namespace MWRender x * numTextures, y * numTextures, numTextures, indexes); + assert( mTerrainGroup->getTerrain(cellX, cellY) == NULL && + "The terrain for this cell already existed" ); mTerrainGroup->defineTerrain(terrainX, terrainY, &terrainData); mTerrainGroup->loadTerrain(terrainX, terrainY, true); @@ -143,6 +159,7 @@ namespace MWRender ESM::Land::LAND_TEXTURE_SIZE, indexes); } + mTerrainGroup->freeTemporaryResources(); } //---------------------------------------------------------------------------------------------- @@ -155,14 +172,14 @@ namespace MWRender { for ( int y = 0; y < 2; y++ ) { - mTerrainGroup->removeTerrain(store->cell->getGridX() * 2 + x, + mTerrainGroup->unloadTerrain(store->cell->getGridX() * 2 + x, store->cell->getGridY() * 2 + y); } } } else { - mTerrainGroup->removeTerrain(store->cell->getGridX(), + mTerrainGroup->unloadTerrain(store->cell->getGridX(), store->cell->getGridY()); } } From 286701e3a5ace50f60d60e0f8dcd9078b043f893 Mon Sep 17 00:00:00 2001 From: Jacob Essex Date: Sat, 11 Feb 2012 20:54:29 +0000 Subject: [PATCH 2/2] Removed the flawed shading, updated textures, removed the need for a unused base texture --- apps/openmw/mwrender/terrain.cpp | 152 +++++++++++++++++++------------ apps/openmw/mwrender/terrain.hpp | 13 ++- 2 files changed, 107 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index a468a44069..710a3ad05e 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -22,12 +22,11 @@ namespace MWRender mTerrainGlobals->setDefaultGlobalColourMapSize(256); //10 (default) didn't seem to be quite enough - mTerrainGlobals->setSkirtSize(32); + mTerrainGlobals->setSkirtSize(128); /* * Here we are pushing the composite map distance beyond the edge - * of the rendered terrain due to light issues (the lighting differs - * so much that it is very noticable + * of the rendered terrain due to not having setup lighting */ mTerrainGlobals->setCompositeMapDistance(ESM::Land::REAL_SIZE*4); @@ -38,6 +37,10 @@ namespace MWRender static_cast(activeProfile); matProfile->setLightmapEnabled(false); + matProfile->setLayerSpecularMappingEnabled(false); + + matProfile->setLayerParallaxMappingEnabled(false); + matProfile->setReceiveDynamicShadowsEnabled(false); //scale the land size if required @@ -85,8 +88,6 @@ namespace MWRender const int cellX = store->cell->getGridX(); const int cellY = store->cell->getGridY(); - Ogre::Terrain::ImportData terrainData = - mTerrainGroup->getDefaultImportSettings(); if ( SPLIT_TERRAIN ) { @@ -97,6 +98,9 @@ namespace MWRender { for ( int y = 0; y < 2; y++ ) { + Ogre::Terrain::ImportData terrainData = + mTerrainGroup->getDefaultImportSettings(); + const int terrainX = cellX * 2 + x; const int terrainY = cellY * 2 + y; @@ -138,6 +142,9 @@ namespace MWRender } else { + Ogre::Terrain::ImportData terrainData = + mTerrainGroup->getDefaultImportSettings(); + //one cell is one terrain segment terrainData.inputFloat = OGRE_ALLOC_T(float, mLandSize*mLandSize, @@ -199,19 +206,17 @@ namespace MWRender 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"); - + //there is one texture that we want to use as a base (i.e. it won't have + //a blend map). This holds the ltex index of that base texture so that + //we know not to include it in the output map + int baseTexture = -1; for ( int y = fromY - 1; y < fromY + size + 1; y++ ) { for ( int x = fromX - 1; x < fromX + size + 1; x++ ) { const uint16_t ltexIndex = getLtexIndexAt(store, x, y); //this is the base texture, so we can ignore this at present - if ( ltexIndex == 0 ) + if ( ltexIndex == baseTexture ) { continue; } @@ -225,21 +230,35 @@ namespace MWRender store->landTextures->ltex.size() > (size_t)ltexIndex - 1 && "LAND.VTEX must be within the bounds of the LTEX array"); - std::string texture = store->landTextures->ltex[ltexIndex-1].texture; - //TODO this is needed due to MWs messed up texture handling - texture = texture.substr(0, texture.rfind(".")) + ".dds"; + std::string texture; + if ( ltexIndex == 0 ) + { + texture = "_land_default.dds"; + } + else + { + texture = store->landTextures->ltex[ltexIndex-1].texture; + //TODO this is needed due to MWs messed up texture handling + texture = texture.substr(0, texture.rfind(".")) + ".dds"; + } const size_t position = terrainData->layerList.size(); terrainData->layerList.push_back(Ogre::Terrain::LayerInstance()); + Ogre::TexturePtr normDisp = getNormalDisp("textures\\" + texture); + terrainData->layerList[position].worldSize = 256; terrainData->layerList[position].textureNames.push_back("textures\\" + texture); + terrainData->layerList[position].textureNames.push_back(normDisp->getName()); - //Normal map. This should be removed but it would require alterations to - //the material generator. Another option would be to use a 1x1 blank texture - terrainData->layerList[position].textureNames.push_back("textures\\" + texture); - - indexes[ltexIndex] = position; + if ( baseTexture == -1 ) + { + baseTexture = ltexIndex; + } + else + { + indexes[ltexIndex] = position; + } } } } @@ -271,9 +290,9 @@ namespace MWRender std::map::const_iterator iter; for ( iter = indexes.begin(); iter != indexes.end(); ++iter ) { - float* pBlend = terrain->getLayerBlendMap(iter->second) - ->getBlendPointer(); - memset(pBlend, 0, sizeof(float) * blendSize * blendSize); + float* pBlend = terrain->getLayerBlendMap(iter->second) + ->getBlendPointer(); + memset(pBlend, 0, sizeof(float) * blendSize * blendSize); } //covert the ltex data into a set of blend maps @@ -288,15 +307,13 @@ namespace MWRender const int relX = texX - fromX; const int relY = texY - fromY; - //this is the ground texture, which is currently the base texture - //so don't alter the splatting map - if ( ltexIndex == 0 ){ + //check if it is the base texture (which isn't in the map) and + //if it is don't bother altering the blend map for it + if ( indexes.find(ltexIndex) == indexes.end() ) + { continue; } - assert (indexes.find(ltexIndex) != indexes.end() && - "Texture layer must exist"); - const int layerIndex = indexes.find(ltexIndex)->second; float* const pBlend = terrain->getLayerBlendMap(layerIndex) @@ -310,7 +327,7 @@ namespace MWRender const int startY = std::max(0, relY*splatSize - blendDist); const int endY = std::min(blendSize, (relY+1)*splatSize + blendDist); - + for ( int blendX = startX; blendX < endX; blendX++ ) { for ( int blendY = startY; blendY < endY; blendY++ ) @@ -321,34 +338,16 @@ namespace MWRender assert(blendY >= 0 && blendY < blendSize && "index must be within texture bounds"); - //calculate the distance from the edge of the square - // to the point we are shading - int distX = relX*splatSize - blendX; - if ( distX < 0 ) - { - distX = std::max(0, blendX - (relX+1)*splatSize); - } - - int distY = relY*splatSize - blendY; - if ( distY < 0 ) - { - distY = std::max(0, blendY - (relY+1)*splatSize); - } - - float blendAmount = blendDist - std::sqrt((float)distX*distX + distY*distY); - blendAmount /= blendDist; - - //this is required as blendDist < sqrt(blendDist*blendDist + blendDist*blendDist) - //this means that the corners are slightly the "wrong" shape but totaly smooth - //shading for the edges - blendAmount = std::max( (float) 0.0, blendAmount); - - assert(blendAmount >= 0 && "Blend should never be negative"); - - //flips the y const int index = blendSize*(blendSize - 1 - blendY) + blendX; - pBlend[index] += blendAmount; - pBlend[index] = std::min((float)1, pBlend[index]); + if ( blendX >= relX*splatSize && blendX < (relX+1)*splatSize && + blendY >= relY*splatSize && blendY < (relY+1)*splatSize ) + { + pBlend[index] = 1; + } + else + { + pBlend[index] = std::max((float)pBlend[index], 0.5f); + } } } @@ -413,4 +412,43 @@ namespace MWRender ->textures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; } + //---------------------------------------------------------------------------------------------- + + Ogre::TexturePtr TerrainManager::getNormalDisp(const std::string& fileName) + { + Ogre::TextureManager* const texMgr = Ogre::TextureManager::getSingletonPtr(); + const std::string normalTextureName = fileName.substr(0, fileName.rfind(".")) + + "_n.dds"; + if ( !texMgr->getByName(normalTextureName).isNull() ) + { + return texMgr->getByName(normalTextureName); + } + + const std::string textureName = "default_terrain_normal"; + if ( !texMgr->getByName(textureName).isNull() ) + { + return texMgr->getByName(textureName); + } + + Ogre::TexturePtr tex = texMgr->createManual( + textureName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, 1, 1, 0, Ogre::PF_BYTE_BGRA); + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer(); + + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + Ogre::uint8* pDest = static_cast(pixelBox.data); + + *pDest++ = 128; // B + *pDest++ = 128; // G + *pDest++ = 128; // R + *pDest++ = 0; // A + + pixelBuffer->unlock(); + + return tex; + } + } diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 195741b0f7..548d00eab3 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -62,7 +62,7 @@ namespace MWRender{ * The distance that the current cell should be shaded into the neighbouring * texture. The distance is in terms of the splat size of a texture */ - static const float TERRAIN_SHADE_DISTANCE = 0.5; + static const float TERRAIN_SHADE_DISTANCE = 0.25f; /** * Setups up the list of textures for part of a cell, using indexes as @@ -107,6 +107,17 @@ namespace MWRender{ * first splat of the current cell */ int getLtexIndexAt(MWWorld::Ptr::CellStore* store, int x, int y); + + /** + * Retrives the texture that is the normal and parallax map for the + * terrain. If it doesn't exist a blank texture is used + * + * The file name of the texture should be the same as the file name of + * the base diffuse texture, but with _n appended before the extension + * + * @param fileName the name of the *diffuse* texture + */ + Ogre::TexturePtr getNormalDisp(const std::string& fileName); };