Replace float type for arguments to create heightfield with int

To reduce amount of computations on the caller side and restrict possible
values.

* verts can't be non-int because it's a number of things.
* worldsize is initially defined as int by ESM::Land::REAL_SIZE.
* Put function to calculate heightfied shift into components to be able to
  reuse by other binaries.
pull/3174/head
elsid 3 years ago
parent d6613d3677
commit 7c5a590890
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -1,6 +1,8 @@
#include "heightfield.hpp" #include "heightfield.hpp"
#include "mtphysics.hpp" #include "mtphysics.hpp"
#include <components/bullethelpers/heightfield.hpp>
#include <osg/Object> #include <osg/Object>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
@ -19,17 +21,17 @@
namespace namespace
{ {
template <class T> template <class T>
auto makeHeights(const T* heights, float sqrtVerts) auto makeHeights(const T* heights, int verts)
-> std::enable_if_t<std::is_same<btScalar, T>::value, std::vector<btScalar>> -> std::enable_if_t<std::is_same<btScalar, T>::value, std::vector<btScalar>>
{ {
return {}; return {};
} }
template <class T> template <class T>
auto makeHeights(const T* heights, float sqrtVerts) auto makeHeights(const T* heights, int verts)
-> std::enable_if_t<!std::is_same<btScalar, T>::value, std::vector<btScalar>> -> std::enable_if_t<!std::is_same<btScalar, T>::value, std::vector<btScalar>>
{ {
return std::vector<btScalar>(heights, heights + static_cast<std::ptrdiff_t>(sqrtVerts * sqrtVerts)); return std::vector<btScalar>(heights, heights + static_cast<std::ptrdiff_t>(verts * verts));
} }
template <class T> template <class T>
@ -50,16 +52,17 @@ namespace
namespace MWPhysics namespace MWPhysics
{ {
HeightField::HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject, PhysicsTaskScheduler* scheduler) HeightField::HeightField(const float* heights, int x, int y, int size, int verts, float minH, float maxH,
const osg::Object* holdObject, PhysicsTaskScheduler* scheduler)
: mHoldObject(holdObject) : mHoldObject(holdObject)
#if BT_BULLET_VERSION < 310 #if BT_BULLET_VERSION < 310
, mHeights(makeHeights(heights, sqrtVerts)) , mHeights(makeHeights(heights, verts))
#endif #endif
, mTaskScheduler(scheduler) , mTaskScheduler(scheduler)
{ {
#if BT_BULLET_VERSION < 310 #if BT_BULLET_VERSION < 310
mShape = std::make_unique<btHeightfieldTerrainShape>( mShape = std::make_unique<btHeightfieldTerrainShape>(
sqrtVerts, sqrtVerts, verts, verts,
getHeights(heights, mHeights), getHeights(heights, mHeights),
1, 1,
minH, maxH, 2, minH, maxH, 2,
@ -67,10 +70,12 @@ namespace MWPhysics
); );
#else #else
mShape = std::make_unique<btHeightfieldTerrainShape>( mShape = std::make_unique<btHeightfieldTerrainShape>(
sqrtVerts, sqrtVerts, heights, minH, maxH, 2, false); verts, verts, heights, minH, maxH, 2, false);
#endif #endif
mShape->setUseDiamondSubdivision(true); mShape->setUseDiamondSubdivision(true);
mShape->setLocalScaling(btVector3(triSize, triSize, 1));
const float scaling = static_cast<float>(size) / static_cast<float>(verts - 1);
mShape->setLocalScaling(btVector3(scaling, scaling, 1));
#if BT_BULLET_VERSION >= 289 #if BT_BULLET_VERSION >= 289
// Accelerates some collision tests. // Accelerates some collision tests.
@ -81,10 +86,8 @@ namespace MWPhysics
mShape->buildAccelerator(); mShape->buildAccelerator();
#endif #endif
btTransform transform(btQuaternion::getIdentity(), const btTransform transform(btQuaternion::getIdentity(),
btVector3((x+0.5f) * triSize * (sqrtVerts-1), BulletHelpers::getHeightfieldShift(x, y, size, minH, maxH));
(y+0.5f) * triSize * (sqrtVerts-1),
(maxH+minH)*0.5f));
mCollisionObject = std::make_unique<btCollisionObject>(); mCollisionObject = std::make_unique<btCollisionObject>();
mCollisionObject->setCollisionShape(mShape.get()); mCollisionObject->setCollisionShape(mShape.get());

@ -23,7 +23,8 @@ namespace MWPhysics
class HeightField class HeightField
{ {
public: public:
HeightField(const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject, PhysicsTaskScheduler* scheduler); HeightField(const float* heights, int x, int y, int size, int verts, float minH, float maxH,
const osg::Object* holdObject, PhysicsTaskScheduler* scheduler);
~HeightField(); ~HeightField();
btCollisionObject* getCollisionObject(); btCollisionObject* getCollisionObject();

@ -472,9 +472,9 @@ namespace MWPhysics
return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight); return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight);
} }
void PhysicsSystem::addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject) void PhysicsSystem::addHeightField(const float* heights, int x, int y, int size, int verts, float minH, float maxH, const osg::Object* holdObject)
{ {
mHeightFields[std::make_pair(x,y)] = std::make_unique<HeightField>(heights, x, y, triSize, sqrtVerts, minH, maxH, holdObject, mTaskScheduler.get()); mHeightFields[std::make_pair(x,y)] = std::make_unique<HeightField>(heights, x, y, size, verts, minH, maxH, holdObject, mTaskScheduler.get());
} }
void PhysicsSystem::removeHeightField (int x, int y) void PhysicsSystem::removeHeightField (int x, int y)

@ -150,7 +150,7 @@ namespace MWPhysics
void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate); void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate);
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, float minH, float maxH, const osg::Object* holdObject); void addHeightField(const float* heights, int x, int y, int size, int verts, float minH, float maxH, const osg::Object* holdObject);
void removeHeightField (int x, int y); void removeHeightField (int x, int y);

@ -383,17 +383,17 @@ namespace MWWorld
{ {
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY); osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
const float verts = ESM::Land::LAND_SIZE; const int verts = ESM::Land::LAND_SIZE;
const float worldsize = ESM::Land::REAL_SIZE; const int worldsize = ESM::Land::REAL_SIZE;
if (data) if (data)
{ {
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get()); mPhysics->addHeightField(data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get());
} }
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], cellX, cellY, worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
} }
if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
{ {

@ -0,0 +1,14 @@
#ifndef OPENMW_COMPONENTS_BULLETHELPERS_HEIGHTFIELD_H
#define OPENMW_COMPONENTS_BULLETHELPERS_HEIGHTFIELD_H
#include <LinearMath/btVector3.h>
namespace BulletHelpers
{
inline btVector3 getHeightfieldShift(int x, int y, int size, float minHeight, float maxHeight)
{
return btVector3((x + 0.5f) * size, (y + 0.5f) * size, (maxHeight + minHeight) * 0.5f);
}
}
#endif
Loading…
Cancel
Save