Add resource manager for ESM::Land to allow data to be unloaded when no longer required

0.6.1
scrawl 8 years ago
parent b898315962
commit 9a3a64f0c4

@ -9,7 +9,7 @@ namespace CSVRender
{
}
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(int cellX, int cellY)
{
std::ostringstream stream;
stream << "#" << cellX << " " << cellY;
@ -23,7 +23,7 @@ namespace CSVRender
const ESM::Land& land = mData.getLand().getRecord(index).get();
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
land.loadData (mask);
return &land;
return new ESMTerrain::LandObject(&land, 0);
}
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)

@ -18,7 +18,7 @@ namespace CSVRender
private:
const CSMWorld::Data& mData;
virtual const ESM::Land* getLand (int cellX, int cellY);
virtual osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY);
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation
renderbin actoranimation landmanager
)
add_openmw_dir (mwinput

@ -516,7 +516,7 @@ namespace MWPhysics
class HeightField
{
public:
HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts)
HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, const osg::Object* holdObject)
{
// find the minimum and maximum heights (needed for bullet)
float minh = heights[0];
@ -544,6 +544,8 @@ namespace MWPhysics
mCollisionObject = new btCollisionObject;
mCollisionObject->setCollisionShape(mShape);
mCollisionObject->setWorldTransform(transform);
mHoldObject = holdObject;
}
~HeightField()
{
@ -558,6 +560,7 @@ namespace MWPhysics
private:
btHeightfieldTerrainShape* mShape;
btCollisionObject* mCollisionObject;
osg::ref_ptr<const osg::Object> mHoldObject;
void operator=(const HeightField&);
HeightField(const HeightField&);
@ -1140,9 +1143,9 @@ namespace MWPhysics
return MovementSolver::traceDown(ptr, position, found->second, mCollisionWorld, maxHeight);
}
void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts)
void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, const osg::Object* holdObject)
{
HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts);
HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts, holdObject);
mHeightFields[std::make_pair(x,y)] = heightfield;
mCollisionWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap,

@ -15,6 +15,7 @@
namespace osg
{
class Group;
class Object;
}
namespace MWRender
@ -80,7 +81,7 @@ namespace MWPhysics
void updatePosition (const MWWorld::Ptr& ptr);
void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts);
void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, const osg::Object* holdObject);
void removeHeightField (int x, int y);

@ -0,0 +1,48 @@
#include "landmanager.hpp"
#include <osg/Stats>
#include <sstream>
#include <components/resource/objectcache.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
namespace MWRender
{
LandManager::LandManager(int loadFlags)
: ResourceManager(NULL)
, mLoadFlags(loadFlags)
{
}
osg::ref_ptr<ESMTerrain::LandObject> LandManager::getLand(int x, int y)
{
std::ostringstream id;
id << x << " " << y;
std::string idstr = id.str();
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(idstr);
if (obj)
return static_cast<ESMTerrain::LandObject*>(obj.get());
else
{
const ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().get<ESM::Land>().search(x,y);
if (!land)
return NULL;
osg::ref_ptr<ESMTerrain::LandObject> landObj (new ESMTerrain::LandObject(land, mLoadFlags));
mCache->addEntryToObjectCache(idstr, landObj.get());
return landObj;
}
}
void LandManager::reportStats(unsigned int frameNumber, osg::Stats *stats)
{
stats->setAttribute(frameNumber, "Land", mCache->getCacheSize());
}
}

@ -0,0 +1,33 @@
#ifndef OPENMW_COMPONENTS_ESMTERRAIN_LANDMANAGER_H
#define OPENMW_COMPONENTS_ESMTERRAIN_LANDMANAGER_H
#include <osg/Object>
#include <components/resource/resourcemanager.hpp>
#include <components/esmterrain/storage.hpp>
namespace ESM
{
struct Land;
}
namespace MWRender
{
class LandManager : public Resource::ResourceManager
{
public:
LandManager(int loadFlags);
/// @note Will return NULL if not found.
osg::ref_ptr<ESMTerrain::LandObject> getLand(int x, int y);
virtual void reportStats(unsigned int frameNumber, osg::Stats* stats);
private:
int mLoadFlags;
};
}
#endif

@ -212,11 +212,13 @@ namespace MWRender
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath));
mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"),
Settings::Manager::getBool("auto use terrain normal maps", "Shaders"),
Settings::Manager::getString("terrain specular map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain specular maps", "Shaders"));
mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(),
new TerrainStorage(mResourceSystem->getVFS(), Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"),
Settings::Manager::getBool("auto use terrain normal maps", "Shaders"),
Settings::Manager::getString("terrain specular map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain specular maps", "Shaders")),
Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get()));
mTerrainStorage, Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get()));
mCamera.reset(new Camera(mViewer->getCamera()));
@ -1055,4 +1057,10 @@ namespace MWRender
SceneUtil::writeScene(node, filename, format);
}
LandManager *RenderingManager::getLandManager() const
{
return mTerrainStorage->getLandManager();
}
}

@ -59,6 +59,8 @@ namespace MWRender
class Pathgrid;
class Camera;
class Water;
class TerrainStorage;
class LandManager;
class RenderingManager : public MWRender::RenderingInterface
{
@ -190,6 +192,8 @@ namespace MWRender
void exportSceneGraph(const MWWorld::Ptr& ptr, const std::string& filename, const std::string& format);
LandManager* getLandManager() const;
private:
void updateProjectionMatrix();
void updateTextureFiltering();
@ -212,6 +216,7 @@ namespace MWRender
std::auto_ptr<Objects> mObjects;
std::auto_ptr<Water> mWater;
std::auto_ptr<Terrain::World> mTerrain;
TerrainStorage* mTerrainStorage;
std::auto_ptr<SkyManager> mSky;
std::auto_ptr<EffectManager> mEffectManager;
osg::ref_ptr<NpcAnimation> mPlayerAnimation;

@ -6,12 +6,22 @@
#include "../mwbase/environment.hpp"
#include "../mwworld/esmstore.hpp"
#include "landmanager.hpp"
namespace MWRender
{
TerrainStorage::TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps)
: ESMTerrain::Storage(vfs, normalMapPattern, normalHeightMapPattern, autoUseNormalMaps, specularMapPattern, autoUseSpecularMaps)
TerrainStorage::TerrainStorage(Resource::ResourceSystem* resourceSystem, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps)
: ESMTerrain::Storage(resourceSystem->getVFS(), normalMapPattern, normalHeightMapPattern, autoUseNormalMaps, specularMapPattern, autoUseSpecularMaps)
, mLandManager(new LandManager(ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX))
, mResourceSystem(resourceSystem)
{
mResourceSystem->addResourceManager(mLandManager.get());
}
TerrainStorage::~TerrainStorage()
{
mResourceSystem->removeResourceManager(mLandManager.get());
}
void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY)
@ -39,22 +49,14 @@ namespace MWRender
maxY += 1;
}
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
LandManager *TerrainStorage::getLandManager() const
{
const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore();
const ESM::Land* land = esmStore.get<ESM::Land>().search(cellX, cellY);
if (!land)
return NULL;
const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX;
if (!land->isDataLoaded(flags))
land->loadData(flags);
// TODO: unload land data when it's no longer needed
return mLandManager.get();
}
return land;
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(int cellX, int cellY)
{
return mLandManager->getLand(cellX, cellY);
}
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
@ -64,4 +66,5 @@ namespace MWRender
return esmStore.get<ESM::LandTexture>().search(index, plugin);
}
}

@ -1,23 +1,37 @@
#ifndef MWRENDER_TERRAINSTORAGE_H
#define MWRENDER_TERRAINSTORAGE_H
#include <memory>
#include <components/esmterrain/storage.hpp>
#include <components/resource/resourcesystem.hpp>
namespace MWRender
{
class LandManager;
/// @brief Connects the ESM Store used in OpenMW with the ESMTerrain storage.
class TerrainStorage : public ESMTerrain::Storage
{
private:
virtual const ESM::Land* getLand (int cellX, int cellY);
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
public:
TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", const std::string& normalHeightMapPatteern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false);
TerrainStorage(Resource::ResourceSystem* resourceSystem, const std::string& normalMapPattern = "", const std::string& normalHeightMapPatteern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false);
~TerrainStorage();
virtual osg::ref_ptr<const ESMTerrain::LandObject> getLand (int cellX, int cellY);
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
/// Get bounds of the whole terrain in cell units
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);
LandManager* getLandManager() const;
private:
std::auto_ptr<LandManager> mLandManager;
Resource::ResourceSystem* mResourceSystem;
};
}

@ -9,6 +9,7 @@
#include <components/misc/resourcehelpers.hpp>
#include <components/nifosg/nifloader.hpp>
#include <components/terrain/world.hpp>
#include <components/esmterrain/storage.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include "../mwbase/environment.hpp"
@ -16,6 +17,7 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwrender/landmanager.hpp"
#include "cellstore.hpp"
#include "manualref.hpp"
@ -46,7 +48,7 @@ namespace MWWorld
{
public:
/// Constructor to be called from the main thread.
PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager, Terrain::World* terrain, bool preloadInstances)
PreloadItem(MWWorld::CellStore* cell, Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager, Resource::KeyframeManager* keyframeManager, Terrain::World* terrain, MWRender::LandManager* landManager, bool preloadInstances)
: mIsExterior(cell->getCell()->isExterior())
, mX(cell->getCell()->getGridX())
, mY(cell->getCell()->getGridY())
@ -54,6 +56,7 @@ namespace MWWorld
, mBulletShapeManager(bulletShapeManager)
, mKeyframeManager(keyframeManager)
, mTerrain(terrain)
, mLandManager(landManager)
, mPreloadInstances(preloadInstances)
, mAbort(false)
{
@ -90,6 +93,7 @@ namespace MWWorld
try
{
mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY));
mPreloadedObjects.push_back(mLandManager->getLand(mX, mY));
}
catch(std::exception& e)
{
@ -151,6 +155,7 @@ namespace MWWorld
Resource::BulletShapeManager* mBulletShapeManager;
Resource::KeyframeManager* mKeyframeManager;
Terrain::World* mTerrain;
MWRender::LandManager* mLandManager;
bool mPreloadInstances;
volatile bool mAbort;
@ -183,10 +188,11 @@ namespace MWWorld
Terrain::World* mTerrain;
};
CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain)
CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain, MWRender::LandManager* landManager)
: mResourceSystem(resourceSystem)
, mBulletShapeManager(bulletShapeManager)
, mTerrain(terrain)
, mLandManager(landManager)
, mExpiryDelay(0.0)
, mMinCacheSize(0)
, mMaxCacheSize(0)
@ -251,7 +257,7 @@ namespace MWWorld
return;
}
osg::ref_ptr<PreloadItem> item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager(), mTerrain, mPreloadInstances));
osg::ref_ptr<PreloadItem> item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager, mResourceSystem->getKeyframeManager(), mTerrain, mLandManager, mPreloadInstances));
mWorkQueue->addWorkItem(item);
mPreloadCells[cell] = PreloadEntry(timestamp, item);

@ -21,6 +21,11 @@ namespace SceneUtil
class UnrefQueue;
}
namespace MWRender
{
class LandManager;
}
namespace MWWorld
{
class CellStore;
@ -28,7 +33,7 @@ namespace MWWorld
class CellPreloader
{
public:
CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain);
CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager, Terrain::World* terrain, MWRender::LandManager* landManager);
~CellPreloader();
/// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell.
@ -64,6 +69,7 @@ namespace MWWorld
Resource::ResourceSystem* mResourceSystem;
Resource::BulletShapeManager* mBulletShapeManager;
Terrain::World* mTerrain;
MWRender::LandManager* mLandManager;
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
osg::ref_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
double mExpiryDelay;

@ -16,6 +16,7 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "../mwrender/landmanager.hpp"
#include "../mwphysics/physicssystem.hpp"
@ -271,26 +272,19 @@ namespace MWWorld
// Load terrain physics first...
if (cell->getCell()->isExterior())
{
const ESM::Land* land =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Land>().search(
cell->getCell()->getGridX(),
cell->getCell()->getGridY()
);
if (land && land->mDataTypes&ESM::Land::DATA_VHGT) {
// Actually only VHGT is needed here, but we'll need the rest for rendering anyway.
// Load everything now to reduce IO overhead.
const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX;
const ESM::Land::LandData *data = land->getLandData (flags);
mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(),
worldsize / (verts-1), verts);
int cellX = cell->getCell()->getGridX();
int cellY = cell->getCell()->getGridY();
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : 0;
if (data)
{
mPhysics->addHeightField (data->mHeights, cellX, cell->getCell()->getGridY(), worldsize / (verts-1), verts, land.get());
}
else
{
static std::vector<float> defaultHeight;
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(),
worldsize / (verts-1), verts);
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, land.get());
}
}
@ -487,7 +481,7 @@ namespace MWWorld
, mPreloadDoors(Settings::Manager::getBool("preload doors", "Cells"))
, mPreloadFastTravel(Settings::Manager::getBool("preload fast travel", "Cells"))
{
mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager(), rendering.getTerrain()));
mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager(), rendering.getTerrain(), rendering.getLandManager()));
mPreloader->setWorkQueue(mRendering.getWorkQueue());
mPreloader->setUnrefQueue(rendering.getUnrefQueue());

@ -16,6 +16,39 @@
namespace ESMTerrain
{
LandObject::LandObject()
{
}
LandObject::LandObject(const ESM::Land *land, int loadFlags)
: mLand(land)
, mLoadFlags(loadFlags)
{
mLand->loadData(mLoadFlags);
}
LandObject::LandObject(const LandObject &copy, const osg::CopyOp &copyop)
{
}
LandObject::~LandObject()
{
if (mLand && mLoadFlags) // only unload if we were responsible for loading to begin with.
mLand->unloadData();
}
const ESM::Land::LandData *LandObject::getData(int flags) const
{
return mLand->getLandData(flags);
}
int LandObject::getPlugin() const
{
return mLand->mPlugin;
}
const float defaultHeight = ESM::Land::DEFAULT_HEIGHT;
Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps)
@ -28,14 +61,6 @@ namespace ESMTerrain
{
}
const ESM::Land::LandData *Storage::getLandData (int cellX, int cellY, int flags)
{
if (const ESM::Land *land = getLand (cellX, cellY))
return land->getLandData (flags);
return 0;
}
bool Storage::getMinMaxHeights(float size, const osg::Vec2f &center, float &min, float &max)
{
assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell");
@ -53,7 +78,9 @@ namespace ESMTerrain
int endRow = startRow + size * (ESM::Land::LAND_SIZE-1) + 1;
int endColumn = startColumn + size * (ESM::Land::LAND_SIZE-1) + 1;
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VHGT))
osg::ref_ptr<const LandObject> land = getLand (cellX, cellY);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : 0;
if (data)
{
min = std::numeric_limits<float>::max();
max = -std::numeric_limits<float>::max();
@ -99,7 +126,9 @@ namespace ESMTerrain
row += ESM::Land::LAND_SIZE-1;
}
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VNML))
osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VNML) : 0;
if (data)
{
normal.x() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
@ -134,7 +163,9 @@ namespace ESMTerrain
row = 0;
}
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VCLR))
osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VCLR) : 0;
if (data)
{
color.r() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f;
color.g() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f;
@ -146,7 +177,6 @@ namespace ESMTerrain
color.g() = 1;
color.b() = 1;
}
}
void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center,
@ -180,9 +210,16 @@ namespace ESMTerrain
float vertX_ = 0; // of current cell corner
for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX)
{
const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT);
const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML);
const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR);
osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
const ESM::Land::LandData *heightData = 0;
const ESM::Land::LandData *normalData = 0;
const ESM::Land::LandData *colourData = 0;
if (land)
{
heightData = land->getData(ESM::Land::DATA_VHGT);
normalData = land->getData(ESM::Land::DATA_VNML);
colourData = land->getData(ESM::Land::DATA_VCLR);
}
int rowStart = 0;
int colStart = 0;
@ -298,15 +335,16 @@ namespace ESMTerrain
assert(x<ESM::Land::LAND_TEXTURE_SIZE);
assert(y<ESM::Land::LAND_TEXTURE_SIZE);
if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX))
osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
const ESM::Land::LandData *data = land ? land->getData(ESM::Land::DATA_VTEX) : 0;
if (data)
{
int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
if (tex == 0)
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin
return std::make_pair(tex, getLand (cellX, cellY)->mPlugin);
return std::make_pair(tex, land->getPlugin());
}
else
return std::make_pair(0,0);
return std::make_pair(0,0);
}
std::string Storage::getTextureName(UniqueTextureId id)
@ -421,8 +459,12 @@ namespace ESMTerrain
int cellX = static_cast<int>(std::floor(worldPos.x() / 8192.f));
int cellY = static_cast<int>(std::floor(worldPos.y() / 8192.f));
const ESM::Land* land = getLand(cellX, cellY);
if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT))
osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
if (!land)
return defaultHeight;
const ESM::Land::LandData* data = land->getData(ESM::Land::DATA_VHGT);
if (!data)
return defaultHeight;
// Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition
@ -461,10 +503,10 @@ namespace ESMTerrain
*/
// Build all 4 positions in normalized cell space, using point-sampled height
osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f);
osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f);
osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f);
osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f);
osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(data, startX, startY) / 8192.f);
osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(data, endX, startY) / 8192.f);
osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(data, endX, endY) / 8192.f);
osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(data, startX, endY) / 8192.f);
// define this plane in terrain space
osg::Plane plane;
// FIXME: deal with differing triangle alignment
@ -496,11 +538,11 @@ namespace ESMTerrain
}
float Storage::getVertexHeight(const ESM::Land *land, int x, int y)
float Storage::getVertexHeight(const ESM::Land::LandData* data, int x, int y)
{
assert(x < ESM::Land::LAND_SIZE);
assert(y < ESM::Land::LAND_SIZE);
return land->getLandData()->mHeights[y * ESM::Land::LAND_SIZE + x];
return data->mHeights[y * ESM::Land::LAND_SIZE + x];
}
Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)

@ -16,25 +16,36 @@ namespace VFS
namespace ESMTerrain
{
/// @brief Feeds data from ESM terrain records (ESM::Land, ESM::LandTexture)
/// into the terrain component, converting it on the fly as needed.
class Storage : public Terrain::Storage
/// @brief Wrapper around ESM::Land with reference counting. The wrapper needs to be held as long as the data is still in use
/// Data will be unloaded when wrapper object is deleted
class LandObject : public osg::Object
{
private:
const ESM::Land* mLand;
int mLoadFlags;
// Not implemented in this class, because we need different Store implementations for game and editor
virtual const ESM::Land* getLand (int cellX, int cellY)= 0;
virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
public:
META_Object(ESMTerrain, LandObject)
const ESM::Land::LandData* getData(int flags) const;
int getPlugin() const;
LandObject();
LandObject(const ESM::Land* land, int loadFlags);
LandObject(const LandObject& copy, const osg::CopyOp& copyop);
virtual ~LandObject();
};
/// @brief Feeds data from ESM terrain records (ESM::Land, ESM::LandTexture)
/// into the terrain component, converting it on the fly as needed.
class Storage : public Terrain::Storage
{
public:
Storage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", const std::string& normalHeightMapPattern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false);
/// Data is loaded first, if necessary. Will return a 0-pointer if there is no data for
/// any of the data types specified via \a flags. Will also return a 0-pointer if there
/// is no land record for the coordinates \a cellX / \a cellY.
const ESM::Land::LandData *getLandData (int cellX, int cellY, int flags);
// Not implemented in this class, because we need different Store implementations for game and editor
virtual osg::ref_ptr<const LandObject> getLand (int cellX, int cellY)= 0;
virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
/// Get bounds of the whole terrain in cell units
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0;
@ -95,7 +106,7 @@ namespace ESMTerrain
void fixColour (osg::Vec4f& colour, int cellX, int cellY, int col, int row);
void averageNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row);
float getVertexHeight (const ESM::Land* land, int x, int y);
float getVertexHeight (const ESM::Land::LandData* data, int x, int y);
// Since plugins can define new texture palettes, we need to know the plugin index too
// in order to retrieve the correct texture name.

@ -259,7 +259,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer)
_resourceStatsChildNum = _switch->getNumChildren();
_switch->addChild(group, false);
const char* statNames[] = {"Compiling", "WorkQueue", "WorkThread", "", "Texture", "StateSet", "Node", "Node Instance", "Shape", "Shape Instance", "Image", "Nif", "Keyframe", "Terrain Cell", "Terrain Texture", "", "UnrefQueue"};
const char* statNames[] = {"Compiling", "WorkQueue", "WorkThread", "", "Texture", "StateSet", "Node", "Node Instance", "Shape", "Shape Instance", "Image", "Nif", "Keyframe", "Terrain Cell", "Terrain Texture", "Land", "", "UnrefQueue"};
int numLines = sizeof(statNames) / sizeof(statNames[0]);

Loading…
Cancel
Save