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

@ -18,7 +18,7 @@ namespace CSVRender
private: private:
const CSMWorld::Data& mData; 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 const ESM::LandTexture* getLandTexture(int index, short plugin);
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); 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 actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation renderbin actoranimation landmanager
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

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

@ -15,6 +15,7 @@
namespace osg namespace osg
{ {
class Group; class Group;
class Object;
} }
namespace MWRender namespace MWRender
@ -80,7 +81,7 @@ namespace MWPhysics
void updatePosition (const MWWorld::Ptr& ptr); 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); 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)); 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(), 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"), mTerrainStorage, Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get()));
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()));
mCamera.reset(new Camera(mViewer->getCamera())); mCamera.reset(new Camera(mViewer->getCamera()));
@ -1055,4 +1057,10 @@ namespace MWRender
SceneUtil::writeScene(node, filename, format); SceneUtil::writeScene(node, filename, format);
} }
LandManager *RenderingManager::getLandManager() const
{
return mTerrainStorage->getLandManager();
}
} }

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

@ -6,12 +6,22 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "landmanager.hpp"
namespace MWRender namespace MWRender
{ {
TerrainStorage::TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) TerrainStorage::TerrainStorage(Resource::ResourceSystem* resourceSystem, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps)
: ESMTerrain::Storage(vfs, normalMapPattern, normalHeightMapPattern, autoUseNormalMaps, specularMapPattern, 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) void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY)
@ -39,22 +49,14 @@ namespace MWRender
maxY += 1; maxY += 1;
} }
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY) LandManager *TerrainStorage::getLandManager() const
{ {
const MWWorld::ESMStore &esmStore = return mLandManager.get();
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 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) const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)
@ -64,4 +66,5 @@ namespace MWRender
return esmStore.get<ESM::LandTexture>().search(index, plugin); return esmStore.get<ESM::LandTexture>().search(index, plugin);
} }
} }

@ -1,23 +1,37 @@
#ifndef MWRENDER_TERRAINSTORAGE_H #ifndef MWRENDER_TERRAINSTORAGE_H
#define MWRENDER_TERRAINSTORAGE_H #define MWRENDER_TERRAINSTORAGE_H
#include <memory>
#include <components/esmterrain/storage.hpp> #include <components/esmterrain/storage.hpp>
#include <components/resource/resourcesystem.hpp>
namespace MWRender namespace MWRender
{ {
class LandManager;
/// @brief Connects the ESM Store used in OpenMW with the ESMTerrain storage. /// @brief Connects the ESM Store used in OpenMW with the ESMTerrain storage.
class TerrainStorage : public 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: 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 /// Get bounds of the whole terrain in cell units
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); 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/misc/resourcehelpers.hpp>
#include <components/nifosg/nifloader.hpp> #include <components/nifosg/nifloader.hpp>
#include <components/terrain/world.hpp> #include <components/terrain/world.hpp>
#include <components/esmterrain/storage.hpp>
#include <components/sceneutil/unrefqueue.hpp> #include <components/sceneutil/unrefqueue.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -16,6 +17,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwrender/landmanager.hpp"
#include "cellstore.hpp" #include "cellstore.hpp"
#include "manualref.hpp" #include "manualref.hpp"
@ -46,7 +48,7 @@ namespace MWWorld
{ {
public: public:
/// Constructor to be called from the main thread. /// 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()) : mIsExterior(cell->getCell()->isExterior())
, mX(cell->getCell()->getGridX()) , mX(cell->getCell()->getGridX())
, mY(cell->getCell()->getGridY()) , mY(cell->getCell()->getGridY())
@ -54,6 +56,7 @@ namespace MWWorld
, mBulletShapeManager(bulletShapeManager) , mBulletShapeManager(bulletShapeManager)
, mKeyframeManager(keyframeManager) , mKeyframeManager(keyframeManager)
, mTerrain(terrain) , mTerrain(terrain)
, mLandManager(landManager)
, mPreloadInstances(preloadInstances) , mPreloadInstances(preloadInstances)
, mAbort(false) , mAbort(false)
{ {
@ -90,6 +93,7 @@ namespace MWWorld
try try
{ {
mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY)); mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY));
mPreloadedObjects.push_back(mLandManager->getLand(mX, mY));
} }
catch(std::exception& e) catch(std::exception& e)
{ {
@ -151,6 +155,7 @@ namespace MWWorld
Resource::BulletShapeManager* mBulletShapeManager; Resource::BulletShapeManager* mBulletShapeManager;
Resource::KeyframeManager* mKeyframeManager; Resource::KeyframeManager* mKeyframeManager;
Terrain::World* mTerrain; Terrain::World* mTerrain;
MWRender::LandManager* mLandManager;
bool mPreloadInstances; bool mPreloadInstances;
volatile bool mAbort; volatile bool mAbort;
@ -183,10 +188,11 @@ namespace MWWorld
Terrain::World* mTerrain; 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) : mResourceSystem(resourceSystem)
, mBulletShapeManager(bulletShapeManager) , mBulletShapeManager(bulletShapeManager)
, mTerrain(terrain) , mTerrain(terrain)
, mLandManager(landManager)
, mExpiryDelay(0.0) , mExpiryDelay(0.0)
, mMinCacheSize(0) , mMinCacheSize(0)
, mMaxCacheSize(0) , mMaxCacheSize(0)
@ -251,7 +257,7 @@ namespace MWWorld
return; 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); mWorkQueue->addWorkItem(item);
mPreloadCells[cell] = PreloadEntry(timestamp, item); mPreloadCells[cell] = PreloadEntry(timestamp, item);

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

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

@ -16,6 +16,39 @@
namespace ESMTerrain 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; 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) 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) bool Storage::getMinMaxHeights(float size, const osg::Vec2f &center, float &min, float &max)
{ {
assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); 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 endRow = startRow + size * (ESM::Land::LAND_SIZE-1) + 1;
int endColumn = startColumn + 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(); min = std::numeric_limits<float>::max();
max = -std::numeric_limits<float>::max(); max = -std::numeric_limits<float>::max();
@ -99,7 +126,9 @@ namespace ESMTerrain
row += ESM::Land::LAND_SIZE-1; 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.x() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; normal.y() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1];
@ -134,7 +163,9 @@ namespace ESMTerrain
row = 0; 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.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; 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.g() = 1;
color.b() = 1; color.b() = 1;
} }
} }
void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center, void Storage::fillVertexBuffers (int lodLevel, float size, const osg::Vec2f& center,
@ -180,9 +210,16 @@ namespace ESMTerrain
float vertX_ = 0; // of current cell corner float vertX_ = 0; // of current cell corner
for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX) for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX)
{ {
const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); const ESM::Land::LandData *heightData = 0;
const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR); 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 rowStart = 0;
int colStart = 0; int colStart = 0;
@ -298,15 +335,16 @@ namespace ESMTerrain
assert(x<ESM::Land::LAND_TEXTURE_SIZE); assert(x<ESM::Land::LAND_TEXTURE_SIZE);
assert(y<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]; int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
if (tex == 0) if (tex == 0)
return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin 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) std::string Storage::getTextureName(UniqueTextureId id)
@ -421,8 +459,12 @@ namespace ESMTerrain
int cellX = static_cast<int>(std::floor(worldPos.x() / 8192.f)); int cellX = static_cast<int>(std::floor(worldPos.x() / 8192.f));
int cellY = static_cast<int>(std::floor(worldPos.y() / 8192.f)); int cellY = static_cast<int>(std::floor(worldPos.y() / 8192.f));
const ESM::Land* land = getLand(cellX, cellY); osg::ref_ptr<const LandObject> land = getLand(cellX, cellY);
if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) if (!land)
return defaultHeight;
const ESM::Land::LandData* data = land->getData(ESM::Land::DATA_VHGT);
if (!data)
return defaultHeight; return defaultHeight;
// Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition
@ -461,10 +503,10 @@ namespace ESMTerrain
*/ */
// Build all 4 positions in normalized cell space, using point-sampled height // 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 v0 (startXTS, startYTS, getVertexHeight(data, startX, startY) / 8192.f);
osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(data, endX, startY) / 8192.f);
osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(data, endX, endY) / 8192.f);
osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(data, startX, endY) / 8192.f);
// define this plane in terrain space // define this plane in terrain space
osg::Plane plane; osg::Plane plane;
// FIXME: deal with differing triangle alignment // 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(x < ESM::Land::LAND_SIZE);
assert(y < 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) Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)

@ -16,25 +16,36 @@ namespace VFS
namespace ESMTerrain namespace ESMTerrain
{ {
/// @brief Feeds data from ESM terrain records (ESM::Land, ESM::LandTexture) /// @brief Wrapper around ESM::Land with reference counting. The wrapper needs to be held as long as the data is still in use
/// into the terrain component, converting it on the fly as needed. /// Data will be unloaded when wrapper object is deleted
class Storage : public Terrain::Storage class LandObject : public osg::Object
{ {
private: private:
const ESM::Land* mLand;
int mLoadFlags;
// Not implemented in this class, because we need different Store implementations for game and editor public:
virtual const ESM::Land* getLand (int cellX, int cellY)= 0; META_Object(ESMTerrain, LandObject)
virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
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: public:
Storage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", const std::string& normalHeightMapPattern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false); 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 // 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 /// Get bounds of the whole terrain in cell units
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0; 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 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); 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 // Since plugins can define new texture palettes, we need to know the plugin index too
// in order to retrieve the correct texture name. // in order to retrieve the correct texture name.

@ -259,7 +259,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer)
_resourceStatsChildNum = _switch->getNumChildren(); _resourceStatsChildNum = _switch->getNumChildren();
_switch->addChild(group, false); _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]); int numLines = sizeof(statNames) / sizeof(statNames[0]);

Loading…
Cancel
Save