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 /*!
34 \class SoModelMatrixElement Inventor/elements/SoModelMatrixElement.h
35 \brief The SoModelMatrixElement class is used to manage the current transformation.
36
37 \ingroup elements
38
39 SoModelMatrixElement contains the object-to-world matrix.
40
41 The world-to-camera transformation is stored in the
42 SoViewingMatrixElement class.
43
44 Note that one thing that can be a little confusing with the API is
45 that SoModelMatrixElement does not contain the same matrix as the
46 OpenGL \c GL_MODELVIEW matrix.
47
48 \sa SoViewingMatrixElement
49 */
50
51 #include "coindefs.h"
52 #include "SbBasicP.h"
53
54 #include <Inventor/elements/SoModelMatrixElement.h>
55 #include <Inventor/SbVec3f.h>
56 #include <cassert>
57
58 // defines for the flags member
59 #define FLG_IDENTITY 0x1 // modelMatrix is identity
60 #define FLG_CULLMATRIX 0x2 // cullMatrix is set
61 #define FLG_COMBINED 0x4 // the combined matrix is calculated
62
63 /*!
64 \fn SoModelMatrixElement::modelMatrix
65
66 FIXME: write doc.
67 */
68
69 /*!
70 \fn SoModelMatrixElement::cullMatrix
71
72 FIXME: write doc.
73 */
74
75 /*!
76 \fn SoModelMatrixElement::combinedMatrix
77
78 FIXME: write doc.
79 */
80
81
82 /*!
83 \fn SoModelMatrixElement::flags
84
85 FIXME: write doc.
86 */
87
88 SO_ELEMENT_SOURCE(SoModelMatrixElement);
89
90 /*!
91 This static method initializes static data for the
92 SoModelMatrixElement class.
93 */
94
95 void
initClass(void)96 SoModelMatrixElement::initClass(void)
97 {
98 SO_ELEMENT_INIT_CLASS(SoModelMatrixElement, inherited);
99 }
100
101 /*!
102 The destructor.
103 */
104
~SoModelMatrixElement(void)105 SoModelMatrixElement::~SoModelMatrixElement(void)
106 {
107 }
108
109 // doc from parent
110 SbBool
matches(const SoElement * element) const111 SoModelMatrixElement::matches(const SoElement * element) const
112 {
113 return inherited::matches(element);
114 }
115
116 /*!
117 Sets the current model matrix to the identity matrix.
118 */
119 void
makeIdentity(SoState * const state,SoNode * const node)120 SoModelMatrixElement::makeIdentity(SoState * const state,
121 SoNode * const node)
122 {
123 SoModelMatrixElement * elem =
124 coin_safe_cast<SoModelMatrixElement *>
125 (
126 SoElement::getElement(state, classStackIndex)
127 );
128 if (elem) {
129 elem->makeEltIdentity();
130 if (node) elem->setNodeId(node);
131 }
132 }
133
134 /*!
135 Sets the current model matrix to \a matrix.
136 */
137 void
set(SoState * const state,SoNode * const node,const SbMatrix & matrix)138 SoModelMatrixElement::set(SoState * const state,
139 SoNode * const node,
140 const SbMatrix & matrix)
141 {
142 SoModelMatrixElement *elem =
143 coin_safe_cast<SoModelMatrixElement *>
144 (
145 SoElement::getElement(state, classStackIndex)
146 );
147
148 if (elem) {
149 elem->setElt(matrix);
150 if (node) elem->setNodeId(node);
151 }
152 }
153
154 /*!
155 Sets the current cull matrix.
156 */
157 void
setCullMatrix(SoState * state,SoNode * COIN_UNUSED_ARG (node),const SbMatrix & matrix)158 SoModelMatrixElement::setCullMatrix(SoState * state, SoNode * COIN_UNUSED_ARG(node),
159 const SbMatrix & matrix)
160 {
161 SoModelMatrixElement * elem =
162 coin_safe_cast<SoModelMatrixElement *>
163 (
164 SoElement::getElement(state, classStackIndex)
165 );
166
167 if (elem) {
168 elem->cullMatrix = matrix;
169 elem->flags |= FLG_CULLMATRIX;
170 elem->flags &= ~FLG_COMBINED;
171 }
172 }
173
174 /*!
175 Multiplies \a matrix into the model matrix.
176 */
177 void
mult(SoState * const state,SoNode * const node,const SbMatrix & matrix)178 SoModelMatrixElement::mult(SoState * const state,
179 SoNode * const node,
180 const SbMatrix &matrix)
181 {
182 SoModelMatrixElement * elem = coin_safe_cast<SoModelMatrixElement *>
183 (
184 SoElement::getElement(state, classStackIndex)
185 );
186
187 if (elem) {
188 elem->multElt(matrix);
189 if (node) elem->addNodeId(node);
190 }
191 }
192
193
194 /*!
195 Appends \a translation to the model matrix.
196 */
197 void
translateBy(SoState * const state,SoNode * const node,const SbVec3f & translation)198 SoModelMatrixElement::translateBy(SoState * const state,
199 SoNode * const node,
200 const SbVec3f &translation)
201 {
202 SoModelMatrixElement * elem = coin_safe_cast<SoModelMatrixElement *>
203 (
204 SoElement::getElement(state, classStackIndex)
205 );
206 if (elem) {
207 elem->translateEltBy(translation);
208 if (node) elem->addNodeId(node);
209 }
210 }
211
212
213 /*!
214 Appends \a rotation to the model matrix.
215 */
216 void
rotateBy(SoState * const state,SoNode * const node,const SbRotation & rotation)217 SoModelMatrixElement::rotateBy(SoState * const state,
218 SoNode * const node,
219 const SbRotation & rotation)
220 {
221 SoModelMatrixElement * elem = coin_safe_cast<SoModelMatrixElement *>
222 (
223 SoElement::getElement(state, classStackIndex)
224 );
225 if (elem) {
226 elem->rotateEltBy(rotation);
227 if (node) elem->addNodeId(node);
228 }
229 }
230
231 /*!
232 Appends \a scaleFactor to the model matrix.
233 */
234 void
scaleBy(SoState * const state,SoNode * const node,const SbVec3f & scaleFactor)235 SoModelMatrixElement::scaleBy(SoState * const state,
236 SoNode * const node,
237 const SbVec3f & scaleFactor)
238 {
239 SoModelMatrixElement * elem = coin_safe_cast<SoModelMatrixElement *>
240 (
241 SoElement::getElement(state, classStackIndex)
242 );
243
244 if (elem) {
245 elem->scaleEltBy(scaleFactor);
246 if (node) elem->addNodeId(node);
247 }
248 }
249
250 /*!
251 Used by SoTransformSeparator to store and restore model matrix.
252 Don't use it for any other reason.
253 */
254 SbMatrix
pushMatrix(SoState * const state)255 SoModelMatrixElement::pushMatrix(SoState * const state)
256 {
257 // use SoState::getElementNoPush() instead of
258 // SoElement::getConstElement() to avoid cache dependencies
259 SoModelMatrixElement * elem = coin_assert_cast<SoModelMatrixElement *>
260 (
261 state->getElementNoPush(classStackIndex)
262 );
263 return elem->pushMatrixElt();
264 }
265
266 /*!
267 Used by SoTransformSeparator to store and restore model matrix.
268 Don't use it for any other reason.
269 */
270 void
popMatrix(SoState * const state,const SbMatrix & matrix)271 SoModelMatrixElement::popMatrix(SoState * const state,
272 const SbMatrix & matrix)
273 {
274 // use SoState::getElementNoPush() instead of
275 // SoElement::getConstElement() to avoid cache dependencies
276 SoModelMatrixElement * elem = coin_assert_cast<SoModelMatrixElement *>
277 (
278 state->getElementNoPush(classStackIndex)
279 );
280 elem->popMatrixElt(matrix);
281 }
282
283 /*!
284 Returns the combined cull and model matrix. This matrix
285 is cached.
286 */
287 const SbMatrix &
getCombinedCullMatrix(SoState * const state)288 SoModelMatrixElement::getCombinedCullMatrix(SoState * const state)
289 {
290 const SoModelMatrixElement * elem = coin_assert_cast<const SoModelMatrixElement *>
291 (
292 SoElement::getConstElement(state, classStackIndex)
293 );
294 if (!(elem->flags & FLG_COMBINED)) {
295 // Need to change this element, so cast away the const (_don't_
296 // use the getElement() method, as it may invoke a
297 // push()). --mortene
298 SoModelMatrixElement * e = const_cast<SoModelMatrixElement *>(elem);
299 e->combinedMatrix = e->modelMatrix;
300 if (e->flags & FLG_CULLMATRIX)
301 e->combinedMatrix.multRight(e->cullMatrix);
302 e->flags |= FLG_COMBINED;
303 }
304 return elem->combinedMatrix;
305 }
306
307 /*!
308 Returns the current model matrix.
309 */
310 const SbMatrix &
get(SoState * const state)311 SoModelMatrixElement::get(SoState * const state)
312 {
313 const SoModelMatrixElement * elem = coin_assert_cast<const SoModelMatrixElement *>
314 (
315 SoElement::getConstElement(state, classStackIndex)
316 );
317 return elem->modelMatrix;
318 }
319
320 /*!
321 Returns the current model matrix. Sets \a isIdentity to
322 TRUE if the model matrix is known to be an identity matrix.
323 */
324 const SbMatrix &
get(SoState * const state,SbBool & isIdentity)325 SoModelMatrixElement::get(SoState * const state,
326 SbBool & isIdentity)
327 {
328 const SoModelMatrixElement * elem = coin_assert_cast<const SoModelMatrixElement *>
329 (
330 SoElement::getConstElement(state, classStackIndex)
331 );
332 if (elem->flags & FLG_IDENTITY) isIdentity = TRUE;
333 else isIdentity = FALSE;
334 return elem->modelMatrix;
335 }
336
337 /*!
338 virtual method which is called from the static method
339 makeIdentity(). Sets element model matrix to identity.
340 */
341 void
makeEltIdentity(void)342 SoModelMatrixElement::makeEltIdentity(void)
343 {
344 this->modelMatrix.makeIdentity();
345 this->flags = FLG_IDENTITY;
346 }
347
348 /*!
349 virtual method which is called from the static method
350 set(). Sets element model matrix to \a matrix.
351 */
352 void
setElt(const SbMatrix & matrix)353 SoModelMatrixElement::setElt(const SbMatrix & matrix)
354 {
355 this->modelMatrix = matrix;
356 this->flags &= ~(FLG_IDENTITY|FLG_COMBINED);
357 }
358
359 /*!
360 virtual method which is called from the static method
361 mult(). Multiplies \a matrix into element model matrix.
362 */
363 void
multElt(const SbMatrix & matrix)364 SoModelMatrixElement::multElt(const SbMatrix & matrix)
365 {
366 this->modelMatrix.multLeft(matrix);
367 this->flags &= ~(FLG_IDENTITY|FLG_COMBINED);
368 }
369
370 /*!
371 virtual method which is called from the static method
372 translateBy(). Appends \a translation to element model matrix.
373 */
374 void
translateEltBy(const SbVec3f & translation)375 SoModelMatrixElement::translateEltBy(const SbVec3f & translation)
376 {
377 SbMatrix matrix = SbMatrix::identity();
378 matrix.setTranslate(translation);
379 this->modelMatrix.multLeft(matrix);
380 this->flags &= ~(FLG_IDENTITY|FLG_COMBINED);
381 }
382
383 /*!
384 virtual method which is called from the static method
385 rotateBy(). Appends \a rotation to element model matrix.
386 */
387 void
rotateEltBy(const SbRotation & rotation)388 SoModelMatrixElement::rotateEltBy(const SbRotation & rotation)
389 {
390 SbMatrix matrix = SbMatrix::identity();
391 matrix.setRotate(rotation);
392 this->modelMatrix.multLeft(matrix);
393 this->flags &= ~(FLG_IDENTITY|FLG_COMBINED);
394 }
395
396 /*!
397 virtual method which is called from the static method
398 scaleBy(). Appends \a scaleFactor to element model matrix.
399 */
400 void
scaleEltBy(const SbVec3f & scaleFactor)401 SoModelMatrixElement::scaleEltBy(const SbVec3f & scaleFactor)
402 {
403 SbMatrix matrix = SbMatrix::identity();
404 matrix.setScale(scaleFactor);
405 this->modelMatrix.multLeft(matrix);
406 this->flags &= ~(FLG_IDENTITY|FLG_COMBINED);
407 }
408
409 /*!
410 virtual method which is called from the static method
411 pushMatrix(). Returns current model matrix.
412 */
413 SbMatrix
pushMatrixElt()414 SoModelMatrixElement::pushMatrixElt()
415 {
416 return this->modelMatrix;
417 }
418
419 /*!
420 virtual method which is called from the static method
421 popMatrix(). Retores model matrix to the matrix returned from
422 pushMatrix().
423 */
424 void
popMatrixElt(const SbMatrix & matrix)425 SoModelMatrixElement::popMatrixElt(const SbMatrix & matrix)
426 {
427 this->modelMatrix = matrix;
428 }
429
430 // doc from parent
431 void
init(SoState * state)432 SoModelMatrixElement::init(SoState * state)
433 {
434 inherited::init(state);
435 this->modelMatrix.makeIdentity();
436 this->flags = FLG_IDENTITY;
437 this->clearNodeIds();
438 }
439
440 // Documented in superclass. Overridden to copy matrices and
441 // accumulate node ids.
442 void
push(SoState * state)443 SoModelMatrixElement::push(SoState * state)
444 {
445 inherited::push(state);
446 const SoModelMatrixElement * prev =
447 coin_assert_cast<SoModelMatrixElement *>
448 (
449 this->getNextInStack()
450 );
451
452 this->modelMatrix = prev->modelMatrix;
453 this->flags = prev->flags;
454 // only copy when needed
455 if (prev->flags & FLG_CULLMATRIX)
456 this->cullMatrix = prev->cullMatrix;
457 if (prev->flags & FLG_COMBINED)
458 this->combinedMatrix = prev->combinedMatrix;
459
460 // make sure node ids are accumulated properly
461 this->copyNodeIds(prev);
462 }
463
464 const SbMatrix &
getModelMatrix(void) const465 SoModelMatrixElement::getModelMatrix(void) const
466 {
467 return this->modelMatrix;
468 }
469
470 #undef FLG_IDENTITY
471 #undef FLG_CULLMATRIX
472 #undef FLG_COMBINED
473