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