#ifndef OPENMW_COMPONENTS_NIFOSG_RIGGEOMETRY_H #define OPENMW_COMPONENTS_NIFOSG_RIGGEOMETRY_H #include #include namespace SceneUtil { class Skeleton; class Bone; // TODO: This class has a lot of issues. // - We require too many workarounds to ensure safety. // - mSourceGeometry should be const, but can not be const because of a use case in shadervisitor.cpp. // - We create useless mGeometry clones in template RigGeometries. // - We do not support compileGLObjects. // - We duplicate some code in MorphGeometry. /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that /// important. /// @note The internal Geometry used for rendering is double buffered, this allows updates to be done in a thread /// safe way while not compromising rendering performance. This is crucial when using osg's default threading model /// of DrawThreadPerContext. class RigGeometry : public osg::Drawable { public: RigGeometry(); RigGeometry(const RigGeometry& copy, const osg::CopyOp& copyop); META_Object(SceneUtil, RigGeometry) // Currently empty as this is difficult to implement. Technically we would need to compile both internal // geometries in separate frames but this method is only called once. Alternatively we could compile just the // static parts of the model. void compileGLObjects(osg::RenderInfo& renderInfo) const override {} struct BoneInfo { std::string mName; osg::BoundingSpheref mBoundSphere; osg::Matrixf mInvBindMatrix; }; using VertexWeight = std::pair; using VertexWeights = std::vector; using BoneWeight = std::pair; using BoneWeights = std::vector; void setBoneInfo(std::vector&& bones); // Convert influences in vertex and weight list per bone format void setInfluences(const std::vector& influences); // Convert influences in bone and weight list per vertex format void setInfluences(const std::vector& influences); /// Initialize this geometry from the source geometry. /// @note The source geometry will not be modified. void setSourceGeometry(osg::ref_ptr sourceGeom); osg::ref_ptr getSourceGeometry() const; void accept(osg::NodeVisitor& nv) override; bool supports(const osg::PrimitiveFunctor&) const override { return true; } void accept(osg::PrimitiveFunctor&) const override; struct CopyBoundingBoxCallback : osg::Drawable::ComputeBoundingBoxCallback { osg::BoundingBox boundingBox; osg::BoundingBox computeBound(const osg::Drawable&) const override { return boundingBox; } }; struct CopyBoundingSphereCallback : osg::Node::ComputeBoundingSphereCallback { osg::BoundingSphere boundingSphere; osg::BoundingSphere computeBound(const osg::Node&) const override { return boundingSphere; } }; private: void cull(osg::NodeVisitor* nv); void updateBounds(osg::NodeVisitor* nv); osg::ref_ptr mGeometry[2]; osg::Geometry* getGeometry(unsigned int frame) const; osg::ref_ptr mSourceGeometry; osg::ref_ptr mSourceTangents; Skeleton* mSkeleton{ nullptr }; osg::ref_ptr mGeomToSkelMatrix; using VertexList = std::vector; struct InfluenceData : public osg::Referenced { std::vector mBones; std::vector> mInfluences; }; osg::ref_ptr mData; std::vector mNodes; unsigned int mLastFrameNumber{ 0 }; bool mBoundsFirstFrame{ true }; bool initFromParentSkeleton(osg::NodeVisitor* nv); void updateGeomToSkelMatrix(const osg::NodePath& nodePath); }; } #endif