1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36 
37 #ifdef HAVE_VRML97
38 
39 /*!
40   \class SoVRMLCollision SoVRMLCollision.h Inventor/VRMLnodes/SoVRMLCollision.h
41   \brief The SoVRMLCollision class is used for collision detection with the avatar.
42 
43   \ingroup VRMLnodes
44 
45   \WEB3DCOPYRIGHT
46 
47   \verbatim
48   Collision {
49     eventIn      MFNode   addChildren
50     eventIn      MFNode   removeChildren
51     exposedField MFNode   children        []
52     exposedField SFBool   collide         TRUE
53     field        SFVec3f  bboxCenter      0 0 0      # (-,)
54     field        SFVec3f  bboxSize        -1 -1 -1   # (0,) or -1,-1,-1
55     field        SFNode   proxy           NULL
56     eventOut     SFTime   collideTime
57   }
58   \endverbatim
59 
60   The Collision node is a grouping node that specifies the collision
61   detection properties for its children (and their descendants),
62   specifies surrogate objects that replace its children during
63   collision detection, and sends events signalling that a collision
64   has occurred between the avatar and the Collision node's geometry or
65   surrogate. By default, all geometric nodes in the scene are
66   collidable with the viewer except IndexedLineSet, PointSet, and
67   Text. Browsers shall detect geometric collisions between the avatar
68   (see SoVRMLNavigationInfo) and the scene's geometry and prevent the
69   avatar from 'entering' the geometry. See 4.13.4, Collision detection
70   and terrain following
71   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.13.4>),
72   for general information on collision detection.
73 
74   If there are no Collision nodes specified in a VRML file, browsers
75   shall detect collisions between the avatar and all objects during
76   navigation.
77 
78   Subclause 4.6.5, Grouping and children nodes
79   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.5>),
80   contains a description of the children, addChildren, and
81   removeChildren fields and eventIns.
82 
83   The Collision node's collide field enables and disables collision
84   detection. If collide is set to FALSE, the children and all
85   descendants of the Collision node shall not be checked for
86   collision, even though they are drawn. This includes any descendent
87   Collision nodes that have collide set to TRUE (i.e., setting collide
88   to FALSE turns collision off for every node below it).
89 
90   Collision nodes with the collide field set to TRUE detect the
91   nearest collision with their descendent geometry (or proxies). When
92   the nearest collision is detected, the collided Collision node sends
93   the time of the collision through its collideTime eventOut. If a
94   Collision node contains a child, descendant, or proxy (see below)
95   that is a Collision node, and both Collision nodes detect that a
96   collision has occurred, both send a collideTime event at the same
97   time. A collideTime event shall be generated if the avatar is
98   colliding with collidable geometry when the Collision node is read
99   from a VRML file or inserted into the transformation hierarchy.
100 
101   The bboxCenter and bboxSize fields specify a bounding box that
102   encloses the Collision node's children. This is a hint that may be
103   used for optimization purposes. The results are undefined if the
104   specified bounding box is smaller than the actual bounding box of
105   the children at any time. A default bboxSize value, (-1, -1, -1),
106   implies that the bounding box is not specified and if needed shall
107   be calculated by the browser. More details on the bboxCenter and
108   bboxSize fields can be found in 4.6.4, Bounding boxes.
109   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.4>),
110 
111   The collision proxy, defined in the proxy field, is any legal
112   children node as described in 4.6.5, Grouping and children nodes,
113   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.5>),
114   that is used as a substitute for the Collision node's children
115   during collision detection. The proxy is used strictly for collision
116   detection; it is not drawn.  If the value of the collide field is
117   TRUE and the proxy field is non-NULL, the proxy field defines the
118   scene on which collision detection is performed. If the proxy value
119   is NULL, collision detection is performed against the children of
120   the Collision node.  If proxy is specified, any descendent children
121   of the Collision node are ignored during collision detection. If
122   children is empty, collide is TRUE, and proxy is specified,
123   collision detection is performed against the proxy but nothing is
124   displayed. In this manner, invisible collision objects may be
125   supported.
126 
127   The collideTime eventOut generates an event specifying the time when
128   the avatar (see SoVRMLNavigationInfo) makes contact with the
129   collidable children or proxy of the Collision node.  An ideal
130   implementation computes the exact time of collision. Implementations
131   may approximate the ideal by sampling the positions of collidable
132   objects and the user. The SoVRMLNavigationInfo node contains additional
133   information for parameters that control the avatar size.
134 */
135 
136 /*!
137   \var SoSFBool SoVRMLCollision::collide
138   Enable/disable collision.
139 */
140 
141 /*!
142   \var SoSFNode SoVRMLCollision::proxy
143   Proxy node(s) used for collision testing.
144 */
145 
146 /*!
147   \var SoSFTime SoVRMLCollision::collideTime
148 
149   An eventOut sent for each collision that occurs.
150 */
151 
152 #include <Inventor/VRMLnodes/SoVRMLCollision.h>
153 
154 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
155 #include <Inventor/actions/SoGLRenderAction.h>
156 #include <Inventor/misc/SoState.h>
157 #include <Inventor/misc/SoChildList.h>
158 #include <Inventor/elements/SoCacheElement.h>
159 
160 #include "nodes/SoSubNodeP.h"
161 #include "profiler/SoNodeProfiling.h"
162 
163 SO_NODE_SOURCE(SoVRMLCollision);
164 
165 // Doc in parent
166 void
initClass(void)167 SoVRMLCollision::initClass(void) // static
168 {
169   SO_NODE_INTERNAL_INIT_CLASS(SoVRMLCollision, SO_VRML97_NODE_TYPE);
170 }
171 
172 /*!
173   Constructor.
174 */
SoVRMLCollision(void)175 SoVRMLCollision::SoVRMLCollision(void)
176 {
177   this->commonConstructor();
178 }
179 
180 /*!
181   Constructor. \a numchildren is the expected number of children.
182 */
SoVRMLCollision(int numchildren)183 SoVRMLCollision::SoVRMLCollision(int numchildren)
184   : inherited(numchildren)
185 {
186   this->commonConstructor();
187 }
188 
189 void
commonConstructor(void)190 SoVRMLCollision::commonConstructor(void)
191 {
192   SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLCollision);
193 
194   SO_VRMLNODE_ADD_EXPOSED_FIELD(collide, (TRUE));
195   SO_VRMLNODE_ADD_FIELD(proxy, (NULL));
196 
197   SO_VRMLNODE_ADD_EVENT_OUT(collideTime);
198 }
199 
200 /*!
201   Destructor.
202 */
~SoVRMLCollision()203 SoVRMLCollision::~SoVRMLCollision() // virtual, protected
204 {
205 }
206 
207 // Doc in parent
208 void
GLRender(SoGLRenderAction * action)209 SoVRMLCollision::GLRender(SoGLRenderAction * action)
210 {
211   SoState * state = action->getState();
212   state->push();
213 
214   int numindices;
215   const int * indices;
216   SoAction::PathCode pathcode = action->getPathCode(numindices, indices);
217 
218   SoNode ** childarray = (SoNode**) this->getChildren()->getArrayPtr();
219 
220   if (pathcode == SoAction::IN_PATH) {
221     int lastchild = indices[numindices - 1];
222     for (int i = 0; i <= lastchild && !action->hasTerminated(); i++) {
223       SoNode * child = childarray[i];
224       action->pushCurPath(i, child);
225       if (action->getCurPathCode() != SoAction::OFF_PATH ||
226           child->affectsState()) {
227         if (!action->abortNow()) {
228           SoNodeProfiling profiling;
229           profiling.preTraversal(action);
230           child->GLRender(action);
231           profiling.postTraversal(action);
232         }
233         else {
234           SoCacheElement::invalidate(state);
235         }
236       }
237       action->popCurPath(pathcode);
238     }
239   }
240   else {
241     action->pushCurPath();
242     int n = this->getChildren()->getLength();
243     for (int i = 0; i < n && !action->hasTerminated(); i++) {
244       action->popPushCurPath(i, childarray[i]);
245       if (action->abortNow()) {
246         // only cache if we do a full traversal
247         SoCacheElement::invalidate(state);
248         break;
249       }
250       SoNodeProfiling profiling;
251       profiling.preTraversal(action);
252       childarray[i]->GLRender(action);
253       profiling.postTraversal(action);
254     }
255     action->popCurPath();
256   }
257   state->pop();
258 }
259 
260 // Doc in parent
261 void
notify(SoNotList * list)262 SoVRMLCollision::notify(SoNotList * list)
263 {
264   inherited::notify(list);
265 }
266 
267 #endif // HAVE_VRML97
268