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 #include <deque>
34 
35 #include <osg/NodeCallback>
36 
37 #include <osgShadow/ShadowMap>
38 #include <osgShadow/ShadowedScene>
39 
40 #include "dart/gui/osg/ShapeFrameNode.hpp"
41 #include "dart/gui/osg/WorldNode.hpp"
42 
43 #include "dart/dynamics/BodyNode.hpp"
44 #include "dart/dynamics/Skeleton.hpp"
45 #include "dart/simulation/World.hpp"
46 
47 namespace dart {
48 namespace gui {
49 namespace osg {
50 
51 class WorldNodeCallback : public ::osg::NodeCallback
52 {
53 public:
operator ()(::osg::Node * node,::osg::NodeVisitor * nv)54   virtual void operator()(::osg::Node* node, ::osg::NodeVisitor* nv)
55   {
56     ::osg::ref_ptr<WorldNode> currentNode = dynamic_cast<WorldNode*>(node);
57 
58     if (currentNode)
59       currentNode->refresh();
60 
61     traverse(node, nv);
62   }
63 };
64 
65 //==============================================================================
WorldNode(std::shared_ptr<dart::simulation::World> world,::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique)66 WorldNode::WorldNode(
67     std::shared_ptr<dart::simulation::World> world,
68     ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique)
69   : mWorld(world),
70     mSimulating(false),
71     mNumStepsPerCycle(1),
72     mViewer(nullptr),
73     mNormalGroup(new ::osg::Group)
74 {
75   // Flags for shadowing; maybe this needs to be global?
76   constexpr int ReceivesShadowTraversalMask = 0x2;
77   constexpr int CastsShadowTraversalMask = 0x1;
78 
79   // Setup shadows
80   // Create a ShadowedScene
81   ::osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene
82       = new osgShadow::ShadowedScene;
83   shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask);
84   shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask);
85 
86   // set the shadowed group
87   mShadowedGroup = shadowedScene.get();
88   mShadowedGroup->getOrCreateStateSet();
89 
90   // Add normal and shadowed groups
91   addChild(mNormalGroup);
92   addChild(mShadowedGroup);
93 
94   setShadowTechnique(shadowTechnique);
95 
96   setUpdateCallback(new WorldNodeCallback);
97 }
98 
99 //==============================================================================
setWorld(std::shared_ptr<dart::simulation::World> newWorld)100 void WorldNode::setWorld(std::shared_ptr<dart::simulation::World> newWorld)
101 {
102   mWorld = newWorld;
103 }
104 
105 //==============================================================================
getWorld() const106 std::shared_ptr<dart::simulation::World> WorldNode::getWorld() const
107 {
108   return mWorld;
109 }
110 
111 //==============================================================================
refresh()112 void WorldNode::refresh()
113 {
114   customPreRefresh();
115 
116   clearChildUtilizationFlags();
117 
118   if (mSimulating)
119   {
120     for (std::size_t i = 0; i < mNumStepsPerCycle; ++i)
121     {
122       customPreStep();
123       mWorld->step();
124       customPostStep();
125     }
126   }
127 
128   refreshSkeletons();
129   refreshSimpleFrames();
130 
131   clearUnusedNodes();
132 
133   customPostRefresh();
134 }
135 
136 //==============================================================================
customPreRefresh()137 void WorldNode::customPreRefresh()
138 {
139   // Do nothing
140 }
141 
142 //==============================================================================
customPostRefresh()143 void WorldNode::customPostRefresh()
144 {
145   // Do nothing
146 }
147 
148 //==============================================================================
customPreStep()149 void WorldNode::customPreStep()
150 {
151   // Do nothing
152 }
153 
154 //==============================================================================
customPostStep()155 void WorldNode::customPostStep()
156 {
157   // Do nothing
158 }
159 
160 //==============================================================================
isSimulating() const161 bool WorldNode::isSimulating() const
162 {
163   return mSimulating;
164 }
165 
166 //==============================================================================
simulate(bool on)167 void WorldNode::simulate(bool on)
168 {
169   mSimulating = on;
170 }
171 
172 //==============================================================================
setNumStepsPerCycle(std::size_t steps)173 void WorldNode::setNumStepsPerCycle(std::size_t steps)
174 {
175   mNumStepsPerCycle = steps;
176 }
177 
178 //==============================================================================
getNumStepsPerCycle() const179 std::size_t WorldNode::getNumStepsPerCycle() const
180 {
181   return mNumStepsPerCycle;
182 }
183 
184 //==============================================================================
~WorldNode()185 WorldNode::~WorldNode()
186 {
187   // Do nothing
188 }
189 
190 //==============================================================================
setupViewer()191 void WorldNode::setupViewer()
192 {
193   // Do nothing
194 }
195 
196 //==============================================================================
clearChildUtilizationFlags()197 void WorldNode::clearChildUtilizationFlags()
198 {
199   for (auto& node_pair : mFrameToNode)
200     node_pair.second->clearUtilization();
201 }
202 
203 //==============================================================================
clearUnusedNodes()204 void WorldNode::clearUnusedNodes()
205 {
206   std::vector<dart::dynamics::Frame*> unused;
207   unused.reserve(mFrameToNode.size());
208 
209   // Find unusued ShapeFrameNodes
210   for (auto& node_pair : mFrameToNode)
211   {
212     ShapeFrameNode* node = node_pair.second;
213     if (node && !node->wasUtilized())
214       unused.push_back(node_pair.first);
215   }
216 
217   // Clear unused ShapeFrameNodes
218   for (dart::dynamics::Frame* frame : unused)
219   {
220     NodeMap::iterator it = mFrameToNode.find(frame);
221     ShapeFrameNode* node = it->second;
222     mNormalGroup->removeChild(node);
223     mShadowedGroup->removeChild(node);
224     mFrameToNode.erase(it);
225   }
226 }
227 
228 //==============================================================================
refreshSkeletons()229 void WorldNode::refreshSkeletons()
230 {
231   if (!mWorld)
232     return;
233 
234   // Apply the recursive Frame refreshing functionality to the root BodyNode of
235   // each Skeleton
236   for (std::size_t i = 0; i < mWorld->getNumSkeletons(); ++i)
237   {
238     const dart::dynamics::SkeletonPtr& skeleton = mWorld->getSkeleton(i);
239     for (std::size_t i = 0; i < skeleton->getNumTrees(); ++i)
240     {
241       refreshBaseFrameNode(skeleton->getRootBodyNode(i));
242     }
243   }
244 }
245 
246 //==============================================================================
refreshSimpleFrames()247 void WorldNode::refreshSimpleFrames()
248 {
249   if (!mWorld)
250     return;
251 
252   for (std::size_t i = 0, end = mWorld->getNumSimpleFrames(); i < end; ++i)
253     refreshBaseFrameNode(mWorld->getSimpleFrame(i).get());
254 }
255 
256 //==============================================================================
refreshBaseFrameNode(dart::dynamics::Frame * frame)257 void WorldNode::refreshBaseFrameNode(dart::dynamics::Frame* frame)
258 {
259   std::deque<dart::dynamics::Frame*> frames;
260   frames.push_back(frame);
261   while (!frames.empty())
262   {
263     dart::dynamics::Frame* nextFrame = frames.front();
264     frames.pop_front();
265     if (nextFrame->isShapeFrame())
266       refreshShapeFrameNode(nextFrame);
267 
268     const std::set<dart::dynamics::Frame*>& childFrames
269         = nextFrame->getChildFrames();
270 
271     for (dart::dynamics::Frame* child : childFrames)
272       frames.push_back(child);
273   }
274 }
275 
276 //==============================================================================
refreshShapeFrameNode(dart::dynamics::Frame * frame)277 void WorldNode::refreshShapeFrameNode(dart::dynamics::Frame* frame)
278 {
279   std::pair<NodeMap::iterator, bool> insertion
280       = mFrameToNode.insert(std::make_pair(frame, nullptr));
281   NodeMap::iterator it = insertion.first;
282   bool inserted = insertion.second;
283 
284   if (!inserted)
285   {
286     ShapeFrameNode* node = it->second;
287     if (!node)
288       return;
289 
290     node->refresh(true);
291 
292     // update the group that ShapeFrameNode should be
293     if ((!node->getShapeFrame()->hasVisualAspect()
294          || !node->getShapeFrame()->getVisualAspect(true)->getShadowed())
295         && node->getParent(0) != mNormalGroup)
296     {
297       mShadowedGroup->removeChild(node);
298       mNormalGroup->addChild(node);
299     }
300     else if (
301         node->getShapeFrame()->hasVisualAspect()
302         && node->getShapeFrame()->getVisualAspect(true)->getShadowed()
303         && node->getParent(0) != mShadowedGroup)
304     {
305       mNormalGroup->removeChild(node);
306       mShadowedGroup->addChild(node);
307     }
308 
309     return;
310   }
311 
312   if (!frame->isShapeFrame())
313   {
314     dtwarn << "[WorldNode::refreshShapeFrameNode] Frame named ["
315            << frame->getName() << "] (" << frame << ") claims to be a "
316            << "ShapeFrame, but failed to be converted. Please report this as a "
317            << "bug!\n";
318     return;
319   }
320 
321   ::osg::ref_ptr<ShapeFrameNode> node
322       = new ShapeFrameNode(frame->asShapeFrame(), this);
323   it->second = node;
324   if (!node->getShapeFrame()->hasVisualAspect()
325       || !node->getShapeFrame()->getVisualAspect(true)->getShadowed())
326   {
327     mNormalGroup->addChild(node);
328   }
329   else
330     mShadowedGroup->addChild(node);
331 }
332 
333 //==============================================================================
isShadowed() const334 bool WorldNode::isShadowed() const
335 {
336   return mShadowed;
337 }
338 
339 //==============================================================================
setShadowTechnique(::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique)340 void WorldNode::setShadowTechnique(
341     ::osg::ref_ptr<osgShadow::ShadowTechnique> shadowTechnique)
342 {
343   if (!shadowTechnique)
344   {
345     mShadowed = false;
346     mShadowedGroup->setShadowTechnique(nullptr);
347   }
348   else
349   {
350     mShadowed = true;
351     mShadowedGroup->setShadowTechnique(shadowTechnique);
352   }
353 }
354 
355 //==============================================================================
getShadowTechnique() const356 ::osg::ref_ptr<osgShadow::ShadowTechnique> WorldNode::getShadowTechnique() const
357 {
358   if (!mShadowed)
359     return nullptr;
360   return mShadowedGroup->getShadowTechnique();
361 }
362 
363 //==============================================================================
364 ::osg::ref_ptr<osgShadow::ShadowTechnique>
createDefaultShadowTechnique(const Viewer * viewer)365 WorldNode::createDefaultShadowTechnique(const Viewer* viewer)
366 {
367   assert(viewer);
368 
369   ::osg::ref_ptr<osgShadow::ShadowMap> sm = new osgShadow::ShadowMap;
370   // increase the resolution of default shadow texture for higher quality
371   auto mapres = static_cast<short>(std::pow(2, 12));
372   sm->setTextureSize(::osg::Vec2s(mapres, mapres));
373   // we are using Light1 because this is the highest one (on up direction)
374   sm->setLight(viewer->getLightSource(0));
375 
376   return sm;
377 }
378 
379 } // namespace osg
380 } // namespace gui
381 } // namespace dart
382