mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-29 21:45:33 +00:00
Expose game object's bounding box in lua api
This commit is contained in:
parent
54a79cfc39
commit
a7b7f99d72
8 changed files with 213 additions and 0 deletions
|
@ -3,6 +3,9 @@
|
|||
#include <components/esm3/loadfact.hpp>
|
||||
#include <components/esm3/loadnpc.hpp>
|
||||
#include <components/lua/luastate.hpp>
|
||||
#include <components/lua/shapes/box.hpp>
|
||||
#include <components/sceneutil/cullsafeboundsvisitor.hpp>
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
@ -10,6 +13,8 @@
|
|||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/scene.hpp"
|
||||
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "luaevents.hpp"
|
||||
|
@ -132,6 +137,14 @@ namespace MWLua
|
|||
[](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asVec3(); });
|
||||
objectT["rotation"] = sol::readonly_property(
|
||||
[](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asRotationVec3(); });
|
||||
objectT["getBoundingBox"] = [](const ObjectT& o) {
|
||||
const MWWorld::Ptr& ptr = o.ptr();
|
||||
SceneUtil::CullSafeBoundsVisitor computeBounds;
|
||||
computeBounds.setTraversalMask(~(MWRender::Mask_ParticleSystem | MWRender::Mask_Effect));
|
||||
ptr.getRefData().getBaseNode()->accept(computeBounds);
|
||||
osg::BoundingBox bb = computeBounds.mBoundingBox;
|
||||
return LuaUtil::Box{ bb.center(), bb._max - bb.center() };
|
||||
};
|
||||
|
||||
objectT["type"] = sol::readonly_property(
|
||||
[types = getTypeToPackageTable(context.mLua->sol())](
|
||||
|
|
|
@ -35,6 +35,7 @@ endif (GIT_CHECKOUT)
|
|||
|
||||
add_component_dir (lua
|
||||
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage
|
||||
shapes/box
|
||||
)
|
||||
|
||||
add_component_dir (l10n
|
||||
|
|
45
components/lua/shapes/box.cpp
Normal file
45
components/lua/shapes/box.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "box.hpp"
|
||||
|
||||
namespace LuaUtil
|
||||
{
|
||||
Box::Box(const osg::Vec3f& center, const osg::Vec3f& halfSize, const osg::Quat& rotation)
|
||||
: mCenter(center)
|
||||
, mHalfSize(halfSize)
|
||||
, mRotation(rotation)
|
||||
{
|
||||
}
|
||||
|
||||
Box::Box(const osg::Matrix& transform)
|
||||
{
|
||||
osg::Quat _;
|
||||
transform.decompose(mCenter, mRotation, mHalfSize, _);
|
||||
}
|
||||
|
||||
std::array<osg::Vec3f, 8> Box::vertices() const
|
||||
{
|
||||
return {
|
||||
mCenter + mRotation * osg::Vec3f(-mHalfSize.x(), -mHalfSize.y(), -mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(mHalfSize.x(), -mHalfSize.y(), -mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(mHalfSize.x(), mHalfSize.y(), -mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(-mHalfSize.x(), mHalfSize.y(), -mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(-mHalfSize.x(), -mHalfSize.y(), mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(mHalfSize.x(), -mHalfSize.y(), mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(mHalfSize.x(), mHalfSize.y(), mHalfSize.z()),
|
||||
mCenter + mRotation * osg::Vec3f(-mHalfSize.x(), mHalfSize.y(), mHalfSize.z()),
|
||||
};
|
||||
}
|
||||
|
||||
osg::Matrix Box::asTransform() const
|
||||
{
|
||||
osg::Matrix transform;
|
||||
transform.preMultTranslate(mCenter);
|
||||
transform.preMultRotate(mRotation);
|
||||
transform.preMultScale(mHalfSize);
|
||||
return transform;
|
||||
}
|
||||
|
||||
bool Box::operator==(const Box& other) const
|
||||
{
|
||||
return mCenter == other.mCenter && mHalfSize == other.mHalfSize && mRotation == other.mRotation;
|
||||
}
|
||||
}
|
31
components/lua/shapes/box.hpp
Normal file
31
components/lua/shapes/box.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef COMPONENTS_LUA_SHAPES_BOX_H
|
||||
#define COMPONENTS_LUA_SHAPES_BOX_H
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <osg/Matrix>
|
||||
#include <osg/Quat>
|
||||
#include <osg/Vec3f>
|
||||
|
||||
namespace LuaUtil
|
||||
{
|
||||
class Box
|
||||
{
|
||||
public:
|
||||
Box(const osg::Vec3f& center, const osg::Vec3f& halfSize, const osg::Quat& rotation = osg::Quat());
|
||||
Box(const osg::Matrix& transform);
|
||||
|
||||
std::array<osg::Vec3f, 8> vertices() const;
|
||||
|
||||
osg::Matrix asTransform() const;
|
||||
|
||||
// TODO: Add `contains` and `intersects` methods
|
||||
|
||||
bool operator==(const Box& other) const;
|
||||
|
||||
osg::Vec3f mCenter;
|
||||
osg::Vec3f mHalfSize;
|
||||
osg::Quat mRotation;
|
||||
};
|
||||
}
|
||||
#endif // COMPONENTS_LUA_SHAPES_BOX_H
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "luastate.hpp"
|
||||
|
||||
#include "shapes/box.hpp"
|
||||
|
||||
namespace sol
|
||||
{
|
||||
template <>
|
||||
|
@ -40,6 +42,11 @@ namespace sol
|
|||
struct is_automagical<LuaUtil::TransformQ> : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_automagical<LuaUtil::Box> : std::false_type
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
namespace LuaUtil
|
||||
|
@ -121,6 +128,30 @@ namespace LuaUtil
|
|||
vec4Type["w"] = sol::readonly_property([](const Vec4& v) -> float { return v.w(); });
|
||||
addVectorMethods<Vec4>(vec4Type);
|
||||
|
||||
// Lua bindings for Box
|
||||
util["box"] = sol::overload([](const Vec3& center, const Vec3& halfSize) { return Box(center, halfSize); },
|
||||
[](const TransformM& transform) { return Box(transform.mM); });
|
||||
sol::usertype<Box> boxType = lua.new_usertype<Box>("Box");
|
||||
boxType["center"] = sol::readonly_property([](const Box& b) { return b.mCenter; });
|
||||
boxType["halfSize"] = sol::readonly_property([](const Box& b) { return b.mHalfSize; });
|
||||
boxType["transform"] = sol::readonly_property([](const Box& b) { return TransformM{ b.asTransform() }; });
|
||||
boxType["vertices"] = sol::readonly_property([lua](const Box& b) {
|
||||
sol::table table(lua, sol::create);
|
||||
const auto vertices = b.vertices();
|
||||
for (size_t i = 0; i < vertices.size(); ++i)
|
||||
table[i + 1] = vertices[i];
|
||||
return table;
|
||||
});
|
||||
boxType[sol::meta_function::equal_to] = [](const Box& a, const Box& b) { return a == b; };
|
||||
boxType[sol::meta_function::to_string] = [](const Box& b) {
|
||||
std::stringstream ss;
|
||||
ss << "Box{ ";
|
||||
ss << "center(" << b.mCenter.x() << ", " << b.mCenter.y() << ", " << b.mCenter.z() << ") ";
|
||||
ss << "halfSize(" << b.mHalfSize.x() << ", " << b.mHalfSize.y() << ", " << b.mHalfSize.z() << ")";
|
||||
ss << " }";
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
// Lua bindings for Color
|
||||
sol::usertype<Misc::Color> colorType = lua.new_usertype<Misc::Color>("Color");
|
||||
colorType["r"] = sol::readonly_property([](const Misc::Color& c) { return c.r(); });
|
||||
|
|
64
components/sceneutil/cullsafeboundsvisitor.hpp
Normal file
64
components/sceneutil/cullsafeboundsvisitor.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_CULLSAFEBOUNDSVISITOR_H
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_CULLSAFEBOUNDSVISITOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/BoundingBox>
|
||||
#include <osg/Matrix>
|
||||
#include <osg/NodeVisitor>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Transform>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
// Computes local bounding box of a node without dirtying itself or any of its children
|
||||
struct CullSafeBoundsVisitor : osg::NodeVisitor
|
||||
{
|
||||
CullSafeBoundsVisitor(osg::NodeVisitor::TraversalMode traversalMode = TRAVERSE_ALL_CHILDREN)
|
||||
: osg::NodeVisitor(traversalMode)
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
mMatrixStack.clear();
|
||||
mBoundingBox.init();
|
||||
}
|
||||
|
||||
void apply(osg::Drawable& drawable)
|
||||
{
|
||||
osg::BoundingBox bbox = drawable.getInitialBound();
|
||||
bbox.expandBy(drawable.computeBoundingBox());
|
||||
applyBoundingBox(bbox);
|
||||
}
|
||||
|
||||
void apply(osg::Transform& transform)
|
||||
{
|
||||
osg::Matrix matrix;
|
||||
if (!mMatrixStack.empty())
|
||||
matrix = mMatrixStack.back();
|
||||
|
||||
mMatrixStack.push_back(matrix);
|
||||
traverse(transform);
|
||||
mMatrixStack.pop_back();
|
||||
}
|
||||
|
||||
void applyBoundingBox(const osg::BoundingBox& bbox)
|
||||
{
|
||||
if (mMatrixStack.empty())
|
||||
{
|
||||
mBoundingBox.expandBy(bbox);
|
||||
}
|
||||
else if (bbox.valid())
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
mBoundingBox.expandBy(bbox.corner(i) * mMatrixStack.back());
|
||||
}
|
||||
}
|
||||
|
||||
osg::BoundingBox mBoundingBox;
|
||||
std::vector<osg::Matrix> mMatrixStack;
|
||||
};
|
||||
}
|
||||
#endif // OPENMW_COMPONENTS_SCENEUTIL_CULLSAFEBOUNDSVISITOR_H
|
|
@ -203,6 +203,11 @@
|
|||
-- @usage -- take 50 coins from `money` and put to the container `cont`
|
||||
-- money:split(50):moveInto(types.Container.content(cont))
|
||||
|
||||
---
|
||||
-- The axis aligned bounding box in local coordinates.
|
||||
-- @function [parent=#GameObject] getBoundingBox
|
||||
-- @param self
|
||||
-- @return openmw.util#Box
|
||||
|
||||
---
|
||||
-- List of GameObjects. Implements [iterables#List](iterables.html#List) of #GameObject
|
||||
|
|
|
@ -397,6 +397,29 @@
|
|||
-- @param #Vector4 v
|
||||
-- @return #Vector4
|
||||
|
||||
---
|
||||
-- Immutable box.
|
||||
-- @type Box
|
||||
-- @field #Vector3 center The center of the box
|
||||
-- @field #Vector3 halfSize The half sizes of the box along each axis
|
||||
-- @field #Transform transform A transformation which encapsulates the boxes center pointer (translation), half sizes (scale), and rotation.
|
||||
-- @field #table vertices Table of the 8 vertices which comprise the box, taking rotation into account
|
||||
|
||||
---
|
||||
-- Creates a new Box with a given center and half sizes. Boxes are immutable and can not be changed after creation.
|
||||
-- @function [parent=#util] Box
|
||||
-- @param #Vector3 center
|
||||
-- @param #Vector3 halfSize in each dimension (x, y, z)
|
||||
-- @return #Box
|
||||
|
||||
---
|
||||
-- Creates a new Box from a given transformation. Boxes are immutable and can not be changed after creation.
|
||||
-- @function [parent=#util] Box
|
||||
-- @param #Transform transform A transformation which encapsulates the boxes center pointer (translation), half sizes (scale), and rotation.
|
||||
-- @return #Box
|
||||
-- @usage
|
||||
-- -- Creates a 1x1x1 length box centered at the origin
|
||||
-- util.box(util.transform.scale(util.vector3(0.5, 0.5, 0.5)))
|
||||
|
||||
---
|
||||
-- Color in RGBA format. All of the component values are in the range [0, 1].
|
||||
|
|
Loading…
Reference in a new issue