1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 13:53:53 +00:00

refactored loading of land data

(cherry picked from commit 69b9eadb52)

Conflicts:
	apps/openmw/mwworld/scene.cpp
	components/esmterrain/storage.cpp
This commit is contained in:
Marc Zinnschlag 2015-08-31 16:13:26 +02:00 committed by cc9cii
parent 4f24c6a7c8
commit c4b34a077e
9 changed files with 111 additions and 83 deletions

View file

@ -841,19 +841,13 @@ void Record<ESM::Land>::print()
std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl;
std::cout << " DataTypes: " << mData.mDataTypes << std::endl; std::cout << " DataTypes: " << mData.mDataTypes << std::endl;
// Seems like this should done with reference counting in the if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes))
// 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; std::cout << " Height Offset: " << data->mHeightOffset << std::endl;
// Lots of missing members. // Lots of missing members.
std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl; std::cout << " Unknown1: " << data->mUnk1 << std::endl;
std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl; std::cout << " Unknown2: " << data->mUnk2 << std::endl;
} }
if (!wasLoaded) mData.unloadData();
} }
template<> template<>

View file

@ -420,8 +420,9 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages)
mState.getWriter().startRecord (record.mLand->sRecordId); mState.getWriter().startRecord (record.mLand->sRecordId);
record.mLand->save (mState.getWriter()); 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); mState.getWriter().endRecord (record.mLand->sRecordId);
} }

View file

@ -130,7 +130,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages&
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); 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 // list texture indices
std::pair<uint16_t, int> key; std::pair<uint16_t, int> key;
@ -138,7 +138,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages&
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i) for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
{ {
key.first = land.mLandData->mTextures[i]; key.first = data->mTextures[i];
mState.mTextureIndices[key] = -1; mState.mTextureIndices[key] = -1;
} }

View file

@ -83,6 +83,9 @@ namespace MWRender
land->loadData(mask); land->loadData(mask);
} }
const ESM::Land::LandData *landData =
land ? land->getLandData (ESM::Land::DATA_WNAM) : 0;
for (int cellY=0; cellY<mCellSize; ++cellY) for (int cellY=0; cellY<mCellSize; ++cellY)
{ {
for (int cellX=0; cellX<mCellSize; ++cellX) for (int cellX=0; cellX<mCellSize; ++cellX)
@ -90,15 +93,14 @@ namespace MWRender
int vertexX = static_cast<int>(float(cellX)/float(mCellSize) * 9); int vertexX = static_cast<int>(float(cellX)/float(mCellSize) * 9);
int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9); int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9);
int texelX = (x-mMinX) * mCellSize + cellX; int texelX = (x-mMinX) * mCellSize + cellX;
int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY); int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY);
unsigned char r,g,b; unsigned char r,g,b;
float y = 0; float y = 0;
if (land && land->mDataTypes & ESM::Land::DATA_WNAM) if (landData)
y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f;
else else
y = (SCHAR_MIN << 4) / 2048.f; y = (SCHAR_MIN << 4) / 2048.f;
if (y < 0) if (y < 0)

View file

@ -236,16 +236,10 @@ namespace MWWorld
// Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Actually only VHGT is needed here, but we'll need the rest for rendering anyway.
// Load everything now to reduce IO overhead. // 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 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); const ESM::Land::LandData *data = land->getLandData (flags);
mPhysics->addHeightField ( mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(),
land->mLandData->mHeights, 0, worldsize / (verts-1), verts);
cell->getCell()->getGridX(),
cell->getCell()->getGridY(),
0,
worldsize / (verts-1),
verts)
;
} }
} }

View file

@ -10,7 +10,7 @@ namespace ESM
{ {
unsigned int Land::sRecordId = REC_LAND; unsigned int Land::sRecordId = REC_LAND;
void Land::LandData::save(ESMWriter &esm) void Land::LandData::save(ESMWriter &esm) const
{ {
if (mDataTypes & Land::DATA_VNML) { if (mDataTypes & Land::DATA_VNML) {
esm.writeHNT("VNML", mNormals, sizeof(mNormals)); 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 int readPos = 0; //bit ugly, but it works
for ( int y1 = 0; y1 < 4; y1++ ) for ( int y1 = 0; y1 < 4; y1++ )
@ -139,7 +139,7 @@ void Land::save(ESMWriter &esm) const
esm.writeHNT("DATA", mFlags); esm.writeHNT("DATA", mFlags);
} }
void Land::loadData(int flags) void Land::loadData(int flags) const
{ {
// Try to load only available data // Try to load only available data
flags = flags & mDataTypes; 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) { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) {
mEsm->getHExact(ptr, size); mEsm->getHExact(ptr, size);
@ -242,4 +242,18 @@ bool Land::isDataLoaded(int flags) const
std::swap (mDataLoaded, land.mDataLoaded); std::swap (mDataLoaded, land.mDataLoaded);
std::swap (mLandData, land.mLandData); 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;
}
} }

View file

@ -35,7 +35,6 @@ struct Land
ESM_Context mContext; ESM_Context mContext;
int mDataTypes; int mDataTypes;
int mDataLoaded;
enum enum
{ {
@ -91,12 +90,10 @@ struct Land
short mUnk1; short mUnk1;
uint8_t mUnk2; uint8_t mUnk2;
void save(ESMWriter &esm); void save(ESMWriter &esm) const;
static void transposeTextureData(uint16_t *in, uint16_t *out); static void transposeTextureData(const uint16_t *in, uint16_t *out);
}; };
LandData *mLandData;
void load(ESMReader &esm); void load(ESMReader &esm);
void save(ESMWriter &esm) const; void save(ESMWriter &esm) const;
@ -105,7 +102,7 @@ struct Land
/** /**
* Actually loads data * Actually loads data
*/ */
void loadData(int flags); void loadData(int flags) const;
/** /**
* Frees memory allocated for land data * Frees memory allocated for land data
@ -122,12 +119,24 @@ struct Land
void swap (Land& 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: private:
/// Loads data and marks it as loaded /// Loads data and marks it as loaded
/// \return true if data is actually loaded from file, false otherwise /// \return true if data is actually loaded from file, false otherwise
/// including the case when data is already loaded /// 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;
}; };
} }

View file

@ -16,6 +16,14 @@
namespace ESMTerrain 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 Ogre::Vector2 &center, float &min, float &max) bool Storage::getMinMaxHeights(float size, const Ogre::Vector2 &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");
@ -30,24 +38,25 @@ namespace ESMTerrain
int cellX = static_cast<int>(origin.x); int cellX = static_cast<int>(origin.x);
int cellY = static_cast<int>(origin.y); int cellY = static_cast<int>(origin.y);
const ESM::Land* land = getLand(cellX, cellY); if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VHGT))
if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT))
return false;
min = std::numeric_limits<float>::max();
max = -std::numeric_limits<float>::max();
for (int row=0; row<ESM::Land::LAND_SIZE; ++row)
{ {
for (int col=0; col<ESM::Land::LAND_SIZE; ++col) min = std::numeric_limits<float>::max();
max = -std::numeric_limits<float>::max();
for (int row=0; row<ESM::Land::LAND_SIZE; ++row)
{ {
float h = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; for (int col=0; col<ESM::Land::LAND_SIZE; ++col)
if (h > max) {
max = h; float h = data->mHeights[col*ESM::Land::LAND_SIZE+row];
if (h < min) if (h > max)
min = h; max = h;
if (h < min)
min = h;
}
} }
return true;
} }
return true;
return false;
} }
void Storage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row) void Storage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row)
@ -72,12 +81,12 @@ namespace ESMTerrain
--cellX; --cellX;
row += ESM::Land::LAND_SIZE-1; 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.x = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; normal.y = data->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.z = data->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
normal.normalise(); normal.normalise();
} }
else else
@ -107,12 +116,12 @@ namespace ESMTerrain
++cellX; ++cellX;
row = 0; 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.r = data->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.g = data->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.b = data->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
} }
else else
{ {
@ -156,9 +165,9 @@ namespace ESMTerrain
float vertX_ = 0; // of current cell corner float vertX_ = 0; // of current cell corner
for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX)
{ {
const ESM::Land* land = getLand(cellX, cellY); const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT);
if (land && !(land->mDataTypes&ESM::Land::DATA_VHGT)) const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML);
land = NULL; const ESM::Land::LandData *colourData = getLandData (cellX, cellY, ESM::Land::DATA_VCLR);
int rowStart = 0; int rowStart = 0;
int colStart = 0; int colStart = 0;
@ -177,16 +186,17 @@ namespace ESMTerrain
{ {
positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192); positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192);
positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192); positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192);
if (land)
positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 2)] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row];
else
positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 2)] = -2048;
if (land && land->mDataTypes&ESM::Land::DATA_VNML) float height = -2048;
if (heightData)
height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row];
positions[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 2)] = height;
if (normalData)
{ {
normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; normal.x = normalData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3];
normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; normal.y = normalData->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.z = normalData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2];
normal.normalise(); normal.normalise();
} }
else else
@ -206,11 +216,11 @@ namespace ESMTerrain
normals[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y; normals[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y;
normals[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z; normals[static_cast<unsigned int>(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z;
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.r = colourData->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.g = colourData->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.b = colourData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f;
} }
else else
{ {
@ -261,13 +271,12 @@ 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);
const ESM::Land* land = getLand(cellX, cellY); if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VTEX))
if (land && (land->mDataTypes&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) 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, land->mPlugin); return std::make_pair(tex, getLand (cellX, cellY)->mPlugin);
} }
else else
return std::make_pair(0,0); return std::make_pair(0,0);
@ -459,7 +468,7 @@ namespace ESMTerrain
{ {
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->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) Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture)

View file

@ -16,11 +16,16 @@ namespace ESMTerrain
private: private:
// 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 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; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
public: public:
/// 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
/// 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;