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 SoMultipleCopy SoMultipleCopy.h Inventor/nodes/SoMultipleCopy.h
35   \brief The SoMultipleCopy class redraws it's children multiple times at different transformations.
36 
37   \ingroup nodes
38 
39   The SoMultipleCopy group node duplicates it's children nodes /
40   subgraphs without using additional memory resources.
41 
42   It can do general transformations (translations, rotation and
43   scaling) for it's children. Apart from transformations, the
44   appearance of it's children will be identical.
45 
46   <b>FILE FORMAT/DEFAULTS:</b>
47   \code
48     MultipleCopy {
49         matrix 1 0 0 0
50         0 1 0 0
51         0 0 1 0
52         0 0 0 1
53     }
54   \endcode
55 
56   \sa SoArray
57 */
58 
59 // *************************************************************************
60 
61 #include <Inventor/nodes/SoMultipleCopy.h>
62 
63 #include <Inventor/actions/SoCallbackAction.h>
64 #include <Inventor/actions/SoSearchAction.h>
65 #include <Inventor/actions/SoGetBoundingBoxAction.h>
66 #include <Inventor/elements/SoBBoxModelMatrixElement.h>
67 #include <Inventor/elements/SoSwitchElement.h>
68 #include <Inventor/misc/SoState.h>
69 #include <Inventor/nodes/SoSwitch.h> // SO_SWITCH_ALL
70 
71 #include "nodes/SoSubNodeP.h"
72 
73 // *************************************************************************
74 
75 /*!
76   \var SoMFMatrix SoMultipleCopy::matrix
77 
78   A set of geometry transformation matrices.
79 
80   The number of duplicated redraws of the child geometry will be the
81   same as the number of matrices specified in this field. Ie, each
82   duplication will be transformed according to a transformation
83   matrix.
84 
85   The default value of the field is to contain just a single identity
86   matrix.
87 */
88 
89 // *************************************************************************
90 
91 SO_NODE_SOURCE(SoMultipleCopy);
92 
93 /*!
94   Constructor.
95 */
SoMultipleCopy(void)96 SoMultipleCopy::SoMultipleCopy(void)
97 {
98   SO_NODE_INTERNAL_CONSTRUCTOR(SoMultipleCopy);
99 
100   SO_NODE_ADD_FIELD(matrix, (SbMatrix::identity()));
101 }
102 
103 /*!
104   Destructor.
105 */
~SoMultipleCopy()106 SoMultipleCopy::~SoMultipleCopy()
107 {
108 }
109 
110 // Doc in superclass.
111 void
initClass(void)112 SoMultipleCopy::initClass(void)
113 {
114   SO_NODE_INTERNAL_INIT_CLASS(SoMultipleCopy, SO_FROM_INVENTOR_1);
115 }
116 
117 // Doc in superclass.
118 void
getBoundingBox(SoGetBoundingBoxAction * action)119 SoMultipleCopy::getBoundingBox(SoGetBoundingBoxAction * action)
120 {
121   // get reference to the box
122   SbXfBox3f & box = action->getXfBoundingBox();
123 
124   // store current bbox
125   SbXfBox3f incomingbox = box;
126 
127   // accumulation variables
128   SbVec3f acccenter(0.0f, 0.0f, 0.0f);
129   int numCenters = 0;
130 
131   // make current box empty to calculate bbox of this separator
132   box.makeEmpty();
133   box.setTransform(SbMatrix::identity());
134 
135   // traverse all children, calculate the local bbox
136   inherited::getBoundingBox(action);
137   SbXfBox3f lbbox = box;
138 
139   // Empty the box again
140   box.makeEmpty();
141   box.setTransform(SbMatrix::identity());
142 
143   for (int i=0; i < matrix.getNum(); i++) {
144     // Apply transformation to the local bbox
145     SbXfBox3f tbbox = lbbox;
146     tbbox.transform(matrix[i]);
147 
148     // Accumulate center
149     acccenter += tbbox.getCenter();
150     numCenters++;
151 
152     // expand box by transformed bbox
153     if (!tbbox.isEmpty()) box.extendBy(tbbox);
154   }
155 
156   // Extend the bbox by the incoming bbox
157   if (!incomingbox.isEmpty()) box.extendBy(incomingbox);
158 
159   if (numCenters != 0) {
160     action->resetCenter();
161     action->setCenter(acccenter / float(numCenters), TRUE);
162   }
163 }
164 
165 // Doc in superclass.
166 void
GLRender(SoGLRenderAction * action)167 SoMultipleCopy::GLRender(SoGLRenderAction * action)
168 {
169   SoMultipleCopy::doAction((SoAction*)action);
170 }
171 
172 // Doc in superclass
173 void
audioRender(SoAudioRenderAction * action)174 SoMultipleCopy::audioRender(SoAudioRenderAction * action)
175 {
176   SoMultipleCopy::doAction((SoAction*)action);
177 }
178 
179 // Doc in superclass.
180 SbBool
affectsState(void) const181 SoMultipleCopy::affectsState(void) const
182 {
183   // state is pushed/popped for each traversal
184   return FALSE;
185 }
186 
187 // Doc in superclass.
188 void
doAction(SoAction * action)189 SoMultipleCopy::doAction(SoAction *action)
190 {
191   for (int i=0; i < matrix.getNum(); i++) {
192     action->getState()->push();
193     SoSwitchElement::set(action->getState(), i);
194     SoModelMatrixElement::mult(action->getState(), this, matrix[i]);
195     inherited::doAction(action);
196     action->getState()->pop();
197   }
198 }
199 
200 // Doc in superclass.
201 void
callback(SoCallbackAction * action)202 SoMultipleCopy::callback(SoCallbackAction *action)
203 {
204   SoMultipleCopy::doAction((SoAction*)action);
205 }
206 
207 // Doc in superclass.
208 void
pick(SoPickAction * action)209 SoMultipleCopy::pick(SoPickAction *action)
210 {
211   // We came across what we think is a bug in TGS/SGI OIV when
212   // implementing picking for this node and testing against the
213   // original Inventor library. The SoPickedPoint class can return the
214   // object space point, normal and texture coordinates. TGS/SGI OIV
215   // do not consider the translation inside this node before returning
216   // the object space data from SoPickedPoint, since the path in
217   // SoPickedPoint does not say anything about on which copy the pick
218   // occured.
219   //
220   // We solved this simply by extending SoPickedPoint for storing both
221   // world space and object space data.
222 
223   SoMultipleCopy::doAction((SoAction*)action);
224 }
225 
226 // Doc in superclass.
227 void
handleEvent(SoHandleEventAction * action)228 SoMultipleCopy::handleEvent(SoHandleEventAction *action)
229 {
230   inherited::handleEvent(action);
231 }
232 
233 // Doc in superclass.
234 void
getMatrix(SoGetMatrixAction * action)235 SoMultipleCopy::getMatrix(SoGetMatrixAction *action)
236 {
237   // path does not specify which copy to traverse
238   inherited::getMatrix(action);
239 }
240 
241 // Doc in superclass.
242 void
search(SoSearchAction * action)243 SoMultipleCopy::search(SoSearchAction *action)
244 {
245   SoState * state = action->getState();
246   state->push();
247   // set Switch element so that subgraphs depending on this element
248   // will traverse all children (it's set during normal traversal in
249   // doAction()).
250   SoSwitchElement::set(action->getState(), SO_SWITCH_ALL);
251   // just use SoGroup::search() to traverse all children.
252   inherited::search(action);
253   state->pop();
254 }
255 
256 // Doc in superclass.
257 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)258 SoMultipleCopy::getPrimitiveCount(SoGetPrimitiveCountAction *action)
259 {
260   SoMultipleCopy::doAction((SoAction*)action);
261 }
262