diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 3193e71a4..5e79e2a09 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -516,21 +516,11 @@ namespace MWPhysics class HeightField { public: - HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, const osg::Object* holdObject) + HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject) { - // find the minimum and maximum heights (needed for bullet) - float minh = heights[0]; - float maxh = heights[0]; - for(int i = 1;i < sqrtVerts*sqrtVerts;++i) - { - float h = heights[i]; - if(h > maxh) maxh = h; - if(h < minh) minh = h; - } - mShape = new btHeightfieldTerrainShape( sqrtVerts, sqrtVerts, heights, 1, - minh, maxh, 2, + minH, maxH, 2, PHY_FLOAT, false ); mShape->setUseDiamondSubdivision(true); @@ -539,7 +529,7 @@ namespace MWPhysics btTransform transform(btQuaternion::getIdentity(), btVector3((x+0.5f) * triSize * (sqrtVerts-1), (y+0.5f) * triSize * (sqrtVerts-1), - (maxh+minh)*0.5f)); + (maxH+minH)*0.5f)); mCollisionObject = new btCollisionObject; mCollisionObject->setCollisionShape(mShape); @@ -1143,9 +1133,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, const osg::Object* holdObject) + void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject) { - HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts, holdObject); + HeightField *heightfield = new HeightField(heights, x, y, triSize, sqrtVerts, minH, maxH, holdObject); mHeightFields[std::make_pair(x,y)] = heightfield; mCollisionWorld->addCollisionObject(heightfield->getCollisionObject(), CollisionType_HeightMap, diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index ae585281b..3312f10a0 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -81,7 +81,7 @@ namespace MWPhysics void updatePosition (const MWWorld::Ptr& ptr); - void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, const osg::Object* holdObject); + void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject); void removeHeightField (int x, int y); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 13546eb3f..3e1227b37 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -278,13 +278,13 @@ namespace MWWorld 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()); + mPhysics->addHeightField (data->mHeights, cellX, cell->getCell()->getGridY(), worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get()); } else { static std::vector defaultHeight; defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT); - mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, land.get()); + mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); } } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 8d57c72eb..72c3eb98d 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -203,16 +203,27 @@ namespace ESM if (reader.isNextSub("VHGT")) { VHGT vhgt; if (condLoad(reader, flags, target->mDataLoaded, DATA_VHGT, &vhgt, sizeof(vhgt))) { + target->mMinHeight = FLT_MAX; + target->mMaxHeight = -FLT_MAX; float rowOffset = vhgt.mHeightOffset; for (int y = 0; y < LAND_SIZE; y++) { rowOffset += vhgt.mHeightData[y * LAND_SIZE]; target->mHeights[y * LAND_SIZE] = rowOffset * HEIGHT_SCALE; + if (rowOffset * HEIGHT_SCALE > target->mMaxHeight) + target->mMaxHeight = rowOffset * HEIGHT_SCALE; + if (rowOffset * HEIGHT_SCALE < target->mMinHeight) + target->mMinHeight = rowOffset * HEIGHT_SCALE; float colOffset = rowOffset; for (int x = 1; x < LAND_SIZE; x++) { colOffset += vhgt.mHeightData[y * LAND_SIZE + x]; target->mHeights[x + y * LAND_SIZE] = colOffset * HEIGHT_SCALE; + + if (colOffset * HEIGHT_SCALE > target->mMaxHeight) + target->mMaxHeight = colOffset * HEIGHT_SCALE; + if (colOffset * HEIGHT_SCALE < target->mMinHeight) + target->mMinHeight = colOffset * HEIGHT_SCALE; } } target->mUnk1 = vhgt.mUnk1; diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 261708893..9f33c37da 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -87,6 +87,8 @@ struct Land float mHeightOffset; // Height in world space for each vertex float mHeights[LAND_NUM_VERTS]; + float mMinHeight; + float mMaxHeight; // 24-bit normals, these aren't always correct though. Edge and corner normals may be garbage. VNML mNormals[LAND_NUM_VERTS * 3]; diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 3ce8f4882..4b489f9ea 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -65,8 +65,6 @@ namespace ESMTerrain { assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); - /// \todo investigate if min/max heights should be stored at load time in ESM::Land instead - osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); int cellX = static_cast(std::floor(origin.x()));