#pragma once #include #include #include #include #include #include #include #include #include #include #include class PoseManager; class BoneSelector { public: explicit BoneSelector(PoseManager* poseMgr); void init(osgViewer::Viewer* viewer, osg::Group* sceneRoot); /// Update bone positions each frame. Only rebuilds geometry when /// selection changes — sphere positions update via vertex array dirty(). void updateVisualization(); std::string pick(float mouseX, float mouseY, osgViewer::Viewer* viewer); void setSelected(const std::string& boneName); const std::string& selected() const { return m_selected; } void setVisible(bool v); bool isVisible() const { return m_visible; } /// Set the model world matrix so bone positions are transformed correctly. void setModelMatrix(const osg::Matrix& m) { m_modelMatrix = m; } private: void buildInitialGeometry(); // called once on init void updatePositions(); // cheap per-frame position update PoseManager* m_poseMgr = nullptr; osg::ref_ptr m_root; osg::ref_ptr m_lines; osg::ref_ptr m_spheres; // Line geometry arrays — updated in place each frame osg::ref_ptr m_lineVerts; osg::ref_ptr m_lineColors; osg::ref_ptr m_lineDrawArrays; // Sphere positions — one MatrixTransform per bone std::vector> m_sphereXforms; std::vector m_sphereBoneNames; std::string m_selected; std::string m_prevSelected; // detect selection changes bool m_visible = true; bool m_geometryBuilt = false; osg::Matrix m_modelMatrix; // model world transform for coordinate conversion };