diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 2ee6c54bb..76c14e728 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -841,19 +841,13 @@ void Record::print() std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl; std::cout << " DataTypes: " << mData.mDataTypes << std::endl; - // Seems like this should done with reference counting in the - // loader to me. But I'm not really knowledgable about this - // record type yet. --Cory - bool wasLoaded = (mData.mDataLoaded != 0); - if (mData.mDataTypes) mData.loadData(mData.mDataTypes); - if (mData.mDataLoaded) - { - std::cout << " Height Offset: " << mData.mLandData->mHeightOffset << std::endl; + if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes)) + { + std::cout << " Height Offset: " << data->mHeightOffset << std::endl; // Lots of missing members. - std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl; - std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; + std::cout << " Unknown1: " << data->mUnk1 << std::endl; + std::cout << " Unknown2: " << data->mUnk2 << std::endl; } - if (!wasLoaded) mData.unloadData(); } template<> diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index f78c57ecd..a21a28c99 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -421,8 +421,9 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) mState.getWriter().startRecord (record.mLand->sRecordId); record.mLand->save (mState.getWriter()); - if(record.mLand->mLandData) - record.mLand->mLandData->save (mState.getWriter()); + + if (const ESM::Land::LandData *data = record.mLand->getLandData (record.mLand->mDataTypes)) + data->save (mState.getWriter()); mState.getWriter().endRecord (record.mLand->sRecordId); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index a4072e4bc..5bf0241ac 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); - if (land.mLandData && land.mDataLoaded & ESM::Land::DATA_VTEX) + if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) { // list texture indices std::pair key; @@ -138,7 +138,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& for (int i=0; imTextures[i]; + key.first = data->mTextures[i]; mState.mTextureIndices[key] = -1; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 890c8444a..97a27ebbc 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -156,6 +156,9 @@ namespace MWRender land->loadData(mask); } + const ESM::Land::LandData *landData = + land ? land->getLandData (ESM::Land::DATA_WNAM) : 0; + for (int cellY=0; cellY(float(cellX)/float(mCellSize) * 9); int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); - int texelX = (x-mMinX) * mCellSize + cellX; int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); unsigned char r,g,b; float y = 0; - if (land && land->mDataTypes & ESM::Land::DATA_WNAM) - y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; + if (landData) + y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; else y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 48e346c14..459b3b6ca 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -250,9 +250,9 @@ namespace MWWorld // 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; - if (!land->isDataLoaded(flags)) - land->loadData(flags); - mPhysics->addHeightField (land->mLandData->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), + + const ESM::Land::LandData *data = land->getLandData (flags); + mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts); } } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index baeca34de..770830fdd 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -10,7 +10,7 @@ namespace ESM { unsigned int Land::sRecordId = REC_LAND; -void Land::LandData::save(ESMWriter &esm) +void Land::LandData::save(ESMWriter &esm) const { if (mDataTypes & Land::DATA_VNML) { esm.writeHNT("VNML", mNormals, sizeof(mNormals)); @@ -55,7 +55,7 @@ void Land::LandData::save(ESMWriter &esm) } } -void Land::LandData::transposeTextureData(uint16_t *in, uint16_t *out) +void Land::LandData::transposeTextureData(const uint16_t *in, uint16_t *out) { int readPos = 0; //bit ugly, but it works for ( int y1 = 0; y1 < 4; y1++ ) @@ -139,7 +139,7 @@ void Land::save(ESMWriter &esm) const esm.writeHNT("DATA", mFlags); } -void Land::loadData(int flags) +void Land::loadData(int flags) const { // Try to load only available data flags = flags & mDataTypes; @@ -201,7 +201,7 @@ void Land::unloadData() } } -bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) +bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { mEsm->getHExact(ptr, size); @@ -242,4 +242,18 @@ bool Land::isDataLoaded(int flags) const std::swap (mDataLoaded, land.mDataLoaded); std::swap (mLandData, land.mLandData); } + + const Land::LandData *Land::getLandData (int flags) const + { + if (!(flags & mDataTypes)) + return 0; + + loadData (flags); + return mLandData; + } + + const Land::LandData *Land::getLandData() const + { + return mLandData; + } } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index e010b170c..64d131ecb 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -35,7 +35,6 @@ struct Land ESM_Context mContext; int mDataTypes; - int mDataLoaded; enum { @@ -91,12 +90,10 @@ struct Land short mUnk1; uint8_t mUnk2; - void save(ESMWriter &esm); - static void transposeTextureData(uint16_t *in, uint16_t *out); + void save(ESMWriter &esm) const; + static void transposeTextureData(const uint16_t *in, uint16_t *out); }; - LandData *mLandData; - void load(ESMReader &esm); void save(ESMWriter &esm) const; @@ -105,7 +102,7 @@ struct Land /** * Actually loads data */ - void loadData(int flags); + void loadData(int flags) const; /** * Frees memory allocated for land data @@ -122,12 +119,24 @@ struct Land void swap (Land& land); + /// Return land data with at least the data types specified in \a flags loaded (if they + /// are available). Will return a 0-pointer if there is no data for any of the + /// specified types. + const LandData *getLandData (int flags) const; + + /// Return land data without loading first anything. Can return a 0-pointer. + const LandData *getLandData() const; + private: /// Loads data and marks it as loaded /// \return true if data is actually loaded from file, false otherwise /// including the case when data is already loaded - bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size); + bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const; + + mutable int mDataLoaded; + + mutable LandData *mLandData; }; } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 5bc56a430..ccfe6d9ee 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -18,6 +18,14 @@ 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 ¢er, float &min, float &max) { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); @@ -32,24 +40,25 @@ namespace ESMTerrain int cellX = static_cast(origin.x()); int cellY = static_cast(origin.y()); - const ESM::Land* land = getLand(cellX, cellY); - if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) - return false; - - min = std::numeric_limits::max(); - max = -std::numeric_limits::max(); - for (int row=0; row::max(); + max = -std::numeric_limits::max(); + for (int row=0; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; - if (h > max) - max = h; - if (h < min) - min = h; + for (int col=0; colmHeights[col*ESM::Land::LAND_SIZE+row]; + if (h > max) + max = h; + if (h < min) + min = h; + } } + return true; } - return true; + + return false; } void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) @@ -74,12 +83,12 @@ namespace ESMTerrain --cellX; row += ESM::Land::LAND_SIZE-1; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VNML)) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + 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.z() = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; normal.normalize(); } else @@ -109,12 +118,12 @@ namespace ESMTerrain ++cellX; row = 0; } - const ESM::Land* land = getLand(cellX, cellY); - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VCLR)) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 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.b() = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; } else { @@ -158,9 +167,9 @@ namespace ESMTerrain float vertX_ = 0; // of current cell corner for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) { - const ESM::Land* land = getLand(cellX, cellY); - if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) - land = NULL; + 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); int rowStart = 0; int colStart = 0; @@ -177,20 +186,22 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; rowmLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; + if (heightData) + height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; (*positions)[static_cast(vertX*numVerts + vertY)] = osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * 8192, (vertY / float(numVerts - 1) - 0.5f) * size * 8192, height); - if (land && land->mDataTypes&ESM::Land::DATA_VNML) + if (normalData) { - normal.x() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z() = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + for (int i=0; i<3; ++i) + normal[i] = normalData->mNormals[arrayIndex+i]; + normal.normalize(); } else @@ -208,11 +219,10 @@ namespace ESMTerrain (*normals)[static_cast(vertX*numVerts + vertY)] = normal; - if (land && land->mDataTypes&ESM::Land::DATA_VCLR) + if (colourData) { - color.r() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b() = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + for (int i=0; i<3; ++i) + color[i] = colourData->mColours[arrayIndex+i] / 255.f; } else { @@ -262,13 +272,12 @@ namespace ESMTerrain assert(xmDataTypes&ESM::Land::DATA_VTEX)) + if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX)) { - int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + 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, land->mPlugin); + return std::make_pair(tex, getLand (cellX, cellY)->mPlugin); } else return std::make_pair(0,0); @@ -447,7 +456,7 @@ namespace ESMTerrain { assert(x < ESM::Land::LAND_SIZE); assert(y < ESM::Land::LAND_SIZE); - return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x]; + return land->getLandData()->mHeights[y * ESM::Land::LAND_SIZE + x]; } Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index debbc59b9..5b8ca953d 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -21,12 +21,17 @@ namespace ESMTerrain private: // 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::Land* getLand (int cellX, int cellY)= 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: Storage(const VFS::Manager* vfs); + /// 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 /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY) = 0;