From d0211acf9e0a086c78c1b259c4636aa758d29290 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Thu, 18 May 2023 11:56:45 +0200 Subject: [PATCH] Fixes bug in terrain loading + collision heightmap works although terrain rendering is 100% broken right now --- apps/openmw/mwrender/renderingmanager.cpp | 9 +++++++- apps/openmw/mwworld/esmstore.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 5 ++-- apps/openmw/mwworld/store.cpp | 4 ++-- components/esm/util.cpp | 7 ++++++ components/esm/util.hpp | 3 +++ components/esm3terrain/storage.cpp | 28 +++++++++++------------ components/esm3terrain/storage.hpp | 4 ++-- components/esm4/loadland.cpp | 14 ++++++++---- components/esm4/loadwrld.cpp | 4 ++-- components/terrain/chunkmanager.cpp | 4 ++-- components/terrain/quadtreeworld.cpp | 10 ++++---- components/terrain/storage.hpp | 4 ++-- components/terrain/terraingrid.cpp | 2 +- 14 files changed, 62 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2cfa5291af..f61ec1c851 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -767,7 +767,14 @@ namespace MWRender if (!enable) mWater->setCullCallback(nullptr); else - mTerrain = getWorldspaceTerrain(worldspace); + { + Terrain::World* newTerrain = getWorldspaceTerrain(worldspace); + if (newTerrain != mTerrain) + { + mTerrain->enable(false); + mTerrain = newTerrain; + } + } mTerrain->enable(enable); } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1aae2011e5..598ec70a5c 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -386,7 +386,6 @@ namespace MWWorld { auto visitorRec = [this](ESM4::Reader& reader) { return ESMStoreImp::readRecord(reader, *this); }; ESM4::ReaderUtils::readAll(reader, visitorRec, [](ESM4::Reader&) {}); - getWritable().updateLandPositions(get()); } void ESMStore::setIdType(const ESM::RefId& id, ESM::RecNameInts type) @@ -449,6 +448,7 @@ namespace MWWorld getWritable().setUp(); getWritable().setUp(); getWritable().setUp(); + getWritable().updateLandPositions(get()); getWritable().preprocessReferences(get()); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c88eeecdda..7bebcaa5a2 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -398,8 +398,9 @@ namespace MWWorld { osg::ref_ptr land = mRendering.getLandManager()->getLand(cellIndex); const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; - const int verts = data->getLandSize(); - const int worldsize = data->getSize(); + const int verts = ESM::getLandSize(worldspace); + const int worldsize = ESM::getCellSize(worldspace); + if (data) { mPhysics->addHeightField(data->getHeights().data(), cellX, cellY, worldsize, verts, diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 2915a3fe66..b323258c2e 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1194,12 +1194,12 @@ namespace MWWorld void Store::updateLandPositions(const Store& cells) { - for (auto it : mStatic) + for (auto& it : mStatic) { const ESM4::Cell* cell = cells.find(it.second.mCell); mLands[cell->getExteriorCellLocation()] = &it.second; } - for (auto it : mDynamic) + for (auto& it : mDynamic) { const ESM4::Cell* cell = cells.find(it.second.mCell); mLands[cell->getExteriorCellLocation()] = &it.second; diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 30a477641e..9c7008ac53 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -1,4 +1,6 @@ #include "util.hpp" +#include +#include osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre) { @@ -14,3 +16,8 @@ osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool } return osg::Vec2(x, y); } + +int ESM::getLandSize(ESM::RefId worldspaceId) +{ + return isEsm4Ext(worldspaceId) ? ESM4::Land::VERTS_PER_SIDE : ESM::Land::LAND_SIZE; +} diff --git a/components/esm/util.hpp b/components/esm/util.hpp index 1bc1119e84..8b0087b881 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -89,6 +89,9 @@ namespace ESM return isEsm4Ext(worldspaceId) ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; } + // Vertex count of a side of a land record + int getLandSize(ESM::RefId worldspaceId); + inline ESM::ExteriorCellLocation positionToExteriorCellLocation( float x, float y, ESM::RefId worldspaceId = ESM::Cell::sDefaultWorldspaceId) { diff --git a/components/esm3terrain/storage.cpp b/components/esm3terrain/storage.cpp index 566c97a990..577983dd57 100644 --- a/components/esm3terrain/storage.cpp +++ b/components/esm3terrain/storage.cpp @@ -76,12 +76,12 @@ namespace ESMTerrain int cellY = static_cast(std::floor(origin.y())); osg::ref_ptr land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace)); const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; + const int landSize = ESM::getLandSize(worldspace); + int startRow = (origin.x() - cellX) * landSize; + int startColumn = (origin.y() - cellY) * landSize; - int startRow = (origin.x() - cellX) * data->getLandSize(); - int startColumn = (origin.y() - cellY) * data->getLandSize(); - - int endRow = startRow + size * (data->getLandSize() - 1) + 1; - int endColumn = startColumn + size * (data->getLandSize() - 1) + 1; + int endRow = startRow + size * (landSize - 1) + 1; + int endColumn = startColumn + size * (landSize - 1) + 1; if (data) { @@ -91,7 +91,7 @@ namespace ESMTerrain { for (int col = startColumn; col < endColumn; ++col) { - float h = data->getHeights()[col * data->getLandSize() + row]; + float h = data->getHeights()[col * landSize + row]; if (h > max) max = h; if (h < min) @@ -112,7 +112,7 @@ namespace ESMTerrain const LandObject* land = getLand(cellLocation, cache); const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VNML) : nullptr; - const int landSize = data ? data->getLandSize() : ESM::Land::LAND_SIZE; + const int landSize = ESM::getLandSize(cellLocation.mWorldspace); while (col >= landSize - 1) { @@ -163,7 +163,7 @@ namespace ESMTerrain { const LandObject* land = getLand(cellLocation, cache); const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VCLR) : nullptr; - const int landSize = data ? data->getLandSize() : ESM::Land::LAND_SIZE; + const int landSize = ESM::getLandSize(cellLocation.mWorldspace); if (col == landSize - 1) { @@ -201,8 +201,9 @@ namespace ESMTerrain int startCellX = static_cast(std::floor(origin.x())); int startCellY = static_cast(std::floor(origin.y())); + const int LandSize = ESM::getLandSize(worldspace); - size_t numVerts = static_cast(size * (ESM::Land::LAND_SIZE - 1) / increment + 1); + size_t numVerts = static_cast(size * (LandSize - 1) / increment + 1); positions->resize(numVerts * numVerts); normals->resize(numVerts * numVerts); @@ -229,7 +230,6 @@ namespace ESMTerrain const ESM::LandData* heightData = nullptr; const ESM::LandData* normalData = nullptr; const ESM::LandData* colourData = nullptr; - const int LandSize = land ? land->getLandSize() : ESM::Land::LAND_SIZE; const int LandSizeInUnits = land ? land->getRealSize() : Constants::CellSizeInUnits; if (land) { @@ -615,14 +615,14 @@ namespace ESMTerrain return info; } - float Storage::getCellWorldSize() + float Storage::getCellWorldSize(ESM::RefId worldspace) { - return static_cast(ESM::Land::REAL_SIZE); + return static_cast(ESM::getCellSize(worldspace)); } - int Storage::getCellVertices() + int Storage::getCellVertices(ESM::RefId worldspace) { - return ESM::Land::LAND_SIZE; + return ESM::getLandSize(worldspace); } int Storage::getBlendmapScale(float chunkSize) diff --git a/components/esm3terrain/storage.hpp b/components/esm3terrain/storage.hpp index a35e9dd7d7..31b77819b9 100644 --- a/components/esm3terrain/storage.hpp +++ b/components/esm3terrain/storage.hpp @@ -113,10 +113,10 @@ namespace ESMTerrain float getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) override; /// Get the transformation factor for mapping cell units to world units. - float getCellWorldSize() override; + float getCellWorldSize(ESM::RefId worldspace) override; /// Get the number of vertices on one side for each cell. Should be (power of two)+1 - int getCellVertices() override; + int getCellVertices(ESM::RefId worldspace) override; int getBlendmapScale(float chunkSize) override; diff --git a/components/esm4/loadland.cpp b/components/esm4/loadland.cpp index 29ccb2ff3b..d7acc47ec0 100644 --- a/components/esm4/loadland.cpp +++ b/components/esm4/loadland.cpp @@ -234,21 +234,27 @@ void ESM4::Land::load(ESM4::Reader& reader) if (!missing) mDataTypes |= LAND_VTEX; - mMinHeight = -200000.f; - mMaxHeight = 200000.f; + mMinHeight = std::numeric_limits::max(); + mMaxHeight = std::numeric_limits::lowest(); float row_offset = mHeightMap.heightOffset; for (int y = 0; y < VERTS_PER_SIDE; y++) { row_offset += mHeightMap.gradientData[y * VERTS_PER_SIDE]; - mHeights[y * VERTS_PER_SIDE] = row_offset * HEIGHT_SCALE; + const float heightY = row_offset * HEIGHT_SCALE; + mHeights[y * VERTS_PER_SIDE] = heightY; + mMinHeight = std::min(mMinHeight, heightY); + mMaxHeight = std::max(mMaxHeight, heightY); float colOffset = row_offset; for (int x = 1; x < VERTS_PER_SIDE; x++) { colOffset += mHeightMap.gradientData[y * VERTS_PER_SIDE + x]; - mHeights[x + y * VERTS_PER_SIDE] = colOffset * HEIGHT_SCALE; + const float heightX = colOffset * HEIGHT_SCALE; + mMinHeight = std::min(mMinHeight, heightX); + mMaxHeight = std::max(mMaxHeight, heightX); + mHeights[x + y * VERTS_PER_SIDE] = heightX; } } } diff --git a/components/esm4/loadwrld.cpp b/components/esm4/loadwrld.cpp index 01a249f103..3b010fbbe6 100644 --- a/components/esm4/loadwrld.cpp +++ b/components/esm4/loadwrld.cpp @@ -27,10 +27,10 @@ #include "loadwrld.hpp" #include -//#include // FIXME: debug only +// #include // FIXME: debug only #include "reader.hpp" -//#include "writer.hpp" +// #include "writer.hpp" void ESM4::World::load(ESM4::Reader& reader) { diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index ef52236acd..03643390bf 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -250,7 +250,7 @@ namespace Terrain if (chunkSize <= 1.f) geometry->setLightListCallback(new SceneUtil::LightListCallback); - unsigned int numVerts = (mStorage->getCellVertices() - 1) * chunkSize / (1 << lod) + 1; + unsigned int numVerts = (mStorage->getCellVertices(mWorldspace) - 1) * chunkSize / (1 << lod) + 1; geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags)); @@ -300,7 +300,7 @@ namespace Terrain } } - geometry->setupWaterBoundingBox(-1, chunkSize * mStorage->getCellWorldSize() / numVerts); + geometry->setupWaterBoundingBox(-1, chunkSize * mStorage->getCellWorldSize(mWorldspace) / numVerts); if (!templateGeometry && compile && mSceneManager->getIncrementalCompileOperation()) { diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 6057c53689..562eb89a00 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -145,7 +145,7 @@ namespace Terrain addChildren(mRootNode); mRootNode->initNeighbours(); - float cellWorldSize = mStorage->getCellWorldSize(); + float cellWorldSize = mStorage->getCellWorldSize(mWorldspace); mRootNode->setInitialBound( osg::BoundingSphere(osg::BoundingBox(osg::Vec3(mMinX * cellWorldSize, mMinY * cellWorldSize, 0), osg::Vec3(mMaxX * cellWorldSize, mMaxY * cellWorldSize, 0)))); @@ -218,7 +218,7 @@ namespace Terrain // height data here. constexpr float minZ = -std::numeric_limits::max(); constexpr float maxZ = std::numeric_limits::max(); - float cellWorldSize = mStorage->getCellWorldSize(); + float cellWorldSize = mStorage->getCellWorldSize(mWorldspace); osg::BoundingBox boundingBox( osg::Vec3f((center.x() - halfSize) * cellWorldSize, (center.y() - halfSize) * cellWorldSize, minZ), osg::Vec3f((center.x() + halfSize) * cellWorldSize, (center.y() + halfSize) * cellWorldSize, maxZ)); @@ -475,7 +475,7 @@ namespace Terrain mRootNode->traverseNodes(vd, viewPoint, &lodCallback); } - const float cellWorldSize = mStorage->getCellWorldSize(); + const float cellWorldSize = ESM::getLandSize(mWorldspace); for (unsigned int i = 0; i < vd->getNumEntries(); ++i) { @@ -486,7 +486,7 @@ namespace Terrain if (mHeightCullCallback && isCullVisitor) updateWaterCullingView(mHeightCullCallback, vd, static_cast(&nv), - mStorage->getCellWorldSize(), !isGridEmpty()); + mStorage->getCellWorldSize(mWorldspace), !isGridEmpty()); vd->resetChanged(); @@ -534,7 +534,7 @@ namespace Terrain std::atomic& abort, Loading::Reporter& reporter) { ensureQuadTreeBuilt(); - const float cellWorldSize = mStorage->getCellWorldSize(); + const float cellWorldSize = mStorage->getCellWorldSize(mWorldspace); ViewData* vd = static_cast(view); vd->setViewPoint(viewPoint); diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index 8f6c00e1c7..db712570ee 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -84,10 +84,10 @@ namespace Terrain virtual float getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) = 0; /// Get the transformation factor for mapping cell units to world units. - virtual float getCellWorldSize() = 0; + virtual float getCellWorldSize(ESM::RefId worldspace) = 0; /// Get the number of vertices on one side for each cell. Should be (power of two)+1 - virtual int getCellVertices() = 0; + virtual int getCellVertices(ESM::RefId worldspace) = 0; virtual int getBlendmapScale(float chunkSize) = 0; }; diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 3b99768cf2..cdbfdea723 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -74,7 +74,7 @@ namespace Terrain if (!node) return nullptr; - const float cellWorldSize = mStorage->getCellWorldSize(); + const float cellWorldSize = mStorage->getCellWorldSize(mWorldspace); osg::ref_ptr pat = new SceneUtil::PositionAttitudeTransform; pat->setPosition(osg::Vec3f(chunkCenter.x() * cellWorldSize, chunkCenter.y() * cellWorldSize, 0.f)); pat->addChild(node);