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