1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef DART_GUI_OSG_WORLDNODE_HPP_
34 #define DART_GUI_OSG_WORLDNODE_HPP_
35 
36 #include <memory>
37 #include <unordered_map>
38 #include <osg/Group>
39 #include <osgShadow/ShadowTechnique>
40 
41 #include "dart/gui/osg/Viewer.hpp"
42 
43 namespace dart {
44 
45 namespace simulation {
46 class World;
47 } // namespace simulation
48 
49 namespace dynamics {
50 class Frame;
51 class Entity;
52 class ShapeFrame;
53 } // namespace dynamics
54 
55 namespace gui {
56 namespace osg {
57 
58 class FrameNode;
59 class ShapeFrameNode;
60 class EntityNode;
61 class Viewer;
62 
63 /// WorldNode class encapsulates a World to be displayed in OpenSceneGraph
64 class WorldNode : public ::osg::Group
65 {
66 public:
67   friend class Viewer;
68 
69   /// Default constructor
70   /// Shadows are disabled by default
71   explicit WorldNode(
72       std::shared_ptr<dart::simulation::World> world = nullptr,
73       ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique = nullptr);
74 
75   /// Set the World that this WorldNode is associated with
76   void setWorld(std::shared_ptr<dart::simulation::World> newWorld);
77 
78   /// Get the World that this WorldNode is associated with
79   std::shared_ptr<dart::simulation::World> getWorld() const;
80 
81   /// This function is called at the beginning of each rendering cycle. It
82   /// updates the tree of Frames and Entities that need to be rendered. It may
83   /// also take a simulation step if the simulation is not paused.
84   ///
85   /// If you want to customize what happens at the beginning of each rendering
86   /// cycle, you can either overload this function, or you can overload
87   /// customUpdate(). This update() function will automatically call
88   /// customUpdate() at the beginning of each rendering cycle. By default,
89   /// customUpdate() does nothing.
90   virtual void refresh();
91 
92   /// If update() is not overloaded, this function will be called at the
93   /// beginning of each rendering cycle. This function can be overloaded to
94   /// customize the behavior of each update. The default behavior is to do
95   /// nothing, so overloading this function will not interfere with the usual
96   /// update() operation.
97   virtual void customPreRefresh();
98 
99   /// If update() is not overloaded, this function will be called at the end of
100   /// each rendering cycle. This function can be overloaded to customize the
101   /// behavior of each update. The default behavior is to do nothing, so
102   /// overloading this function will not interfere with the usual update()
103   /// operation.
104   virtual void customPostRefresh();
105 
106   /// If update() is not overloaded, this function will be called at the
107   /// beginning of each simulation step. This function can be overloaded to
108   /// customize the behavior of each step. The default behavior is to do
109   /// nothing, so overloading this function will not interfere with the usual
110   /// update() operation. This will not get called if the simulation is paused.
111   virtual void customPreStep();
112 
113   /// If update() is not overloaded, this function will be called at the end of
114   /// each simulation step. This function can be overloaded to customize the
115   /// behavior of each step. The default behavior is to do nothing, so
116   /// overloading this function will not interfere with the usual update()
117   /// operation. This will not get called if the simulation is paused.
118   virtual void customPostStep();
119 
120   /// Returns true iff the WorldNode is stepping between render cycles
121   bool isSimulating() const;
122 
123   /// Pass in true to take steps between render cycles; pass in false to turn
124   /// off steps between render cycles.
125   void simulate(bool on);
126 
127   /// Set the number of steps to take between each render cycle (only if the
128   /// simulation is not paused)
129   void setNumStepsPerCycle(std::size_t steps);
130 
131   /// Get the number of steps that will be taken between each render cycle (only
132   /// if the simulation is not paused)
133   std::size_t getNumStepsPerCycle() const;
134 
135   /// Get whether the WorldNode is casting shadows
136   bool isShadowed() const;
137 
138   /// Set the ShadowTechnique
139   /// If you wish to disable shadows, pass a nullptr
140   void setShadowTechnique(
141       ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique = nullptr);
142 
143   /// Get the current ShadowTechnique
144   /// nullptr is there are no shadows
145   ::osg::ref_ptr<osgShadow::ShadowTechnique> getShadowTechnique() const;
146 
147   /// Helper function to create a default ShadowTechnique given a Viewer
148   /// the default ShadowTechnique is ShadowMap
149   static ::osg::ref_ptr<osgShadow::ShadowTechnique>
150   createDefaultShadowTechnique(const Viewer* viewer);
151 
152   /// Destructor
153   virtual ~WorldNode();
154 
155 protected:
156   /// Called when this world gets added to an dart::gui::osg::Viewer. Override
157   /// this function to customize the way your WorldNode starts up in an
158   /// dart::gui::osg::Viewer. Default behavior does nothing.
159   virtual void setupViewer();
160 
161   /// Clear the utilization flags of each child node
162   void clearChildUtilizationFlags();
163 
164   /// Clear any nodes whose utilization flags were not triggered on this render
165   /// cycle
166   void clearUnusedNodes();
167 
168   /// Refresh all the Skeleton rendering data
169   void refreshSkeletons();
170 
171   /// Refresh all the custom Frame rendering data
172   void refreshSimpleFrames();
173 
174   void refreshBaseFrameNode(dart::dynamics::Frame* frame);
175 
176   void refreshShapeFrameNode(dart::dynamics::Frame* frame);
177 
178   using NodeMap = std::
179       unordered_map<dart::dynamics::Frame*, ::osg::ref_ptr<ShapeFrameNode>>;
180 
181   /// Map from Frame pointers to FrameNode pointers
182   NodeMap mFrameToNode;
183 
184   /// The World that this WorldNode is associated with
185   std::shared_ptr<dart::simulation::World> mWorld;
186 
187   /// True iff simulation is active
188   bool mSimulating;
189 
190   /// Number of steps to take between rendering cycles
191   std::size_t mNumStepsPerCycle;
192 
193   /// Viewer that this WorldNode is inside of
194   Viewer* mViewer;
195 
196   /// OSG group for non-shadowed objects
197   ::osg::ref_ptr<::osg::Group> mNormalGroup;
198 
199   /// OSG group for shadowed objects
200   ::osg::ref_ptr<::osgShadow::ShadowedScene> mShadowedGroup;
201 
202   /// Whether the shadows are enabled
203   bool mShadowed;
204 };
205 
206 } // namespace osg
207 } // namespace gui
208 } // namespace dart
209 
210 #endif // DART_GUI_OSG_WORLDNODE_HPP_
211