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