Expose game object's bounding box in lua api

simplify_debugging
glassmancody.info 2 years ago
parent 54a79cfc39
commit a7b7f99d72

@ -3,6 +3,9 @@
#include <components/esm3/loadfact.hpp> #include <components/esm3/loadfact.hpp>
#include <components/esm3/loadnpc.hpp> #include <components/esm3/loadnpc.hpp>
#include <components/lua/luastate.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/cellstore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -10,6 +13,8 @@
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/scene.hpp" #include "../mwworld/scene.hpp"
#include "../mwrender/vismask.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "luaevents.hpp" #include "luaevents.hpp"
@ -132,6 +137,14 @@ namespace MWLua
[](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asVec3(); }); [](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asVec3(); });
objectT["rotation"] = sol::readonly_property( objectT["rotation"] = sol::readonly_property(
[](const ObjectT& o) -> osg::Vec3f { return o.ptr().getRefData().getPosition().asRotationVec3(); }); [](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( objectT["type"] = sol::readonly_property(
[types = getTypeToPackageTable(context.mLua->sol())]( [types = getTypeToPackageTable(context.mLua->sol())](

@ -35,6 +35,7 @@ endif (GIT_CHECKOUT)
add_component_dir (lua add_component_dir (lua
luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage luastate scriptscontainer asyncpackage utilpackage serialization configuration l10n storage
shapes/box
) )
add_component_dir (l10n add_component_dir (l10n

@ -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;
}
}

@ -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 "luastate.hpp"
#include "shapes/box.hpp"
namespace sol namespace sol
{ {
template <> template <>
@ -40,6 +42,11 @@ namespace sol
struct is_automagical<LuaUtil::TransformQ> : std::false_type struct is_automagical<LuaUtil::TransformQ> : std::false_type
{ {
}; };
template <>
struct is_automagical<LuaUtil::Box> : std::false_type
{
};
} }
namespace LuaUtil namespace LuaUtil
@ -121,6 +128,30 @@ namespace LuaUtil
vec4Type["w"] = sol::readonly_property([](const Vec4& v) -> float { return v.w(); }); vec4Type["w"] = sol::readonly_property([](const Vec4& v) -> float { return v.w(); });
addVectorMethods<Vec4>(vec4Type); 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 // Lua bindings for Color
sol::usertype<Misc::Color> colorType = lua.new_usertype<Misc::Color>("Color"); sol::usertype<Misc::Color> colorType = lua.new_usertype<Misc::Color>("Color");
colorType["r"] = sol::readonly_property([](const Misc::Color& c) { return c.r(); }); colorType["r"] = sol::readonly_property([](const Misc::Color& c) { return c.r(); });

@ -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` -- @usage -- take 50 coins from `money` and put to the container `cont`
-- money:split(50):moveInto(types.Container.content(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 -- List of GameObjects. Implements [iterables#List](iterables.html#List) of #GameObject

@ -397,6 +397,29 @@
-- @param #Vector4 v -- @param #Vector4 v
-- @return #Vector4 -- @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]. -- Color in RGBA format. All of the component values are in the range [0, 1].

Loading…
Cancel
Save