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