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_MANIPULATORS
38
39 /*!
40 \class SoPointLightManip SoPointLightManip.h Inventor/manips/SoPointLightManip.h
41 \brief The SoPointLightManip class is used to manipulate point light nodes.
42
43 \ingroup manips
44
45 A manipulator is used by replacing the node you want to edit in the
46 graph with the manipulator. Draggers are used to to manipulate the
47 node. When manipulation is finished, the node is put back into the
48 graph, replacing the manipulator.
49
50 <center>
51 \image html pointlight.png "Example of PointLight Manipulator"
52 </center>
53 */
54
55 /*!
56 \var SoFieldSensor * SoPointLightManip::locationFieldSensor
57 \COININTERNAL
58 */
59
60 /*!
61 \var SoFieldSensor * SoPointLightManip::colorFieldSensor
62 \COININTERNAL
63 */
64
65 /*!
66 \var SoChildList * SoPointLightManip::children
67 \COININTERNAL
68 */
69
70 #include <Inventor/manips/SoPointLightManip.h>
71
72 #include <Inventor/draggers/SoPointLightDragger.h>
73 #include <Inventor/actions/SoGLRenderAction.h>
74 #include <Inventor/actions/SoPickAction.h>
75 #include <Inventor/actions/SoGetMatrixAction.h>
76 #include <Inventor/actions/SoGetBoundingBoxAction.h>
77 #include <Inventor/actions/SoHandleEventAction.h>
78 #include <Inventor/actions/SoCallbackAction.h>
79 #include <Inventor/actions/SoSearchAction.h>
80 #include <Inventor/nodes/SoGroup.h>
81 #include <Inventor/nodes/SoMaterial.h>
82 #include <Inventor/misc/SoChildList.h>
83 #include <Inventor/sensors/SoFieldSensor.h>
84 #include <Inventor/SoNodeKitPath.h>
85
86 #if COIN_DEBUG
87 #include <Inventor/errors/SoDebugError.h>
88 #endif // COIN_DEBUG
89
90 #include "nodes/SoSubNodeP.h"
91
92 class SoPointLightManipP {
93 public:
94 };
95
96 SO_NODE_SOURCE(SoPointLightManip);
97
98
99 // Documented in superclass
100 void
initClass(void)101 SoPointLightManip::initClass(void)
102 {
103 SO_NODE_INTERNAL_INIT_CLASS(SoPointLightManip, SO_FROM_INVENTOR_1);
104 }
105
106 /*!
107 The constructor. Creates a default dragger.
108 */
SoPointLightManip(void)109 SoPointLightManip::SoPointLightManip(void)
110 {
111 this->children = new SoChildList(this);
112
113 SO_NODE_INTERNAL_CONSTRUCTOR(SoPointLightManip);
114
115 this->locationFieldSensor = new SoFieldSensor(SoPointLightManip::fieldSensorCB, this);
116 this->locationFieldSensor->setPriority(0);
117
118 this->colorFieldSensor = new SoFieldSensor(SoPointLightManip::fieldSensorCB, this);
119 this->colorFieldSensor->setPriority(0);
120
121 this->attachSensors(TRUE);
122 this->setDragger(new SoPointLightDragger);
123 }
124
125 /*!
126 The destructor.
127 */
~SoPointLightManip()128 SoPointLightManip::~SoPointLightManip()
129 {
130 this->setDragger(NULL);
131
132 delete this->colorFieldSensor;
133 delete this->locationFieldSensor;
134
135 delete this->children;
136 }
137
138 /*!
139 The method can be used to replace the dragger with your own dragger.
140 */
141 void
setDragger(SoDragger * newdragger)142 SoPointLightManip::setDragger(SoDragger * newdragger)
143 {
144 SoDragger * olddragger = this->getDragger();
145 if (olddragger) {
146 olddragger->removeValueChangedCallback(SoPointLightManip::valueChangedCB, this);
147 this->children->remove(0);
148 }
149 if (newdragger != NULL) {
150 if (this->children->getLength() > 0) {
151 this->children->set(0, newdragger);
152 }
153 else {
154 this->children->append(newdragger);
155 }
156 SoPointLightManip::fieldSensorCB(this, NULL);
157 newdragger->addValueChangedCallback(SoPointLightManip::valueChangedCB, this);
158 }
159 }
160
161 /*!
162 Returns the current dragger.
163 \sa setDragger()
164 */
165 SoDragger *
getDragger(void)166 SoPointLightManip::getDragger(void)
167 {
168 if (this->children->getLength() > 0) {
169 SoNode * node = (*children)[0];
170 if (node->isOfType(SoDragger::getClassTypeId()))
171 return (SoDragger *)node;
172 else {
173 #if COIN_DEBUG
174 SoDebugError::post("SoPointLightManip::getDragger",
175 "Child is not a dragger!");
176 #endif // debug
177 }
178 }
179 return NULL;
180 }
181
182 /*!
183 Replaces the node specified by \a path with this manipulator.
184 The manipulator will copy the field data from the node, to make
185 it affect the state in the same way as the node.
186 */
187 SbBool
replaceNode(SoPath * path)188 SoPointLightManip::replaceNode(SoPath * path)
189 {
190 SoFullPath * fullpath = (SoFullPath *)path;
191 SoNode * fulltail = fullpath->getTail();
192 if (!fulltail->isOfType(SoPointLight::getClassTypeId())) {
193 #if COIN_DEBUG
194 SoDebugError::post("SoPointLightManip::replaceNode",
195 "End of path is not a SoPointLight");
196 #endif // debug
197 return FALSE;
198 }
199 SoNode * tail = path->getTail();
200 if (tail->isOfType(SoBaseKit::getClassTypeId())) {
201 SoBaseKit * kit = (SoBaseKit *) ((SoNodeKitPath *)path)->getTail();
202 SbString partname = kit->getPartString(path);
203 if (partname != "") {
204 SoPointLight * oldpart = (SoPointLight *) kit->getPart(partname, TRUE);
205 if (oldpart != NULL) {
206 this->attachSensors(FALSE);
207 this->transferFieldValues(oldpart, this);
208 this->attachSensors(TRUE);
209 SoPointLightManip::fieldSensorCB(this, NULL);
210 kit->setPart(partname, this);
211 return TRUE;
212 }
213 else {
214 return FALSE;
215 }
216 }
217 }
218 if (fullpath->getLength() < 2) {
219 #if COIN_DEBUG
220 SoDebugError::post("SoPointLightManip::replaceNode",
221 "Path is too short");
222 #endif // debug
223 return FALSE;
224 }
225 SoNode * parent = fullpath->getNodeFromTail(1);
226 if (!parent->isOfType(SoGroup::getClassTypeId())) {
227 #if COIN_DEBUG
228 SoDebugError::post("SoPointLightManip::replaceNode",
229 "Parent node is not a group");
230 #endif // debug
231 return FALSE;
232 }
233 this->ref();
234 this->attachSensors(FALSE);
235 this->transferFieldValues((SoPointLight *)fulltail, this);
236 this->attachSensors(TRUE);
237 SoPointLightManip::fieldSensorCB(this, NULL);
238
239 ((SoGroup *)parent)->replaceChild(fulltail, this);
240 this->unrefNoDelete();
241 return TRUE;
242 }
243
244 // Documented in superclass
245 void
doAction(SoAction * action)246 SoPointLightManip::doAction(SoAction * action)
247 {
248 int numindices;
249 const int * indices;
250 if (action->getPathCode(numindices, indices) == SoAction::IN_PATH) {
251 this->children->traverseInPath(action, numindices, indices);
252 }
253 else {
254 this->children->traverse(action);
255 }
256 }
257
258 // Documented in superclass
259 void
callback(SoCallbackAction * action)260 SoPointLightManip::callback(SoCallbackAction * action)
261 {
262 SoPointLightManip::doAction(action);
263 SoPointLight::callback(action);
264 }
265
266 // Documented in superclass
267 void
GLRender(SoGLRenderAction * action)268 SoPointLightManip::GLRender(SoGLRenderAction * action)
269 {
270 SoPointLightManip::doAction(action);
271 SoPointLight::GLRender(action);
272 }
273
274 // Documented in superclass
275 void
getBoundingBox(SoGetBoundingBoxAction * action)276 SoPointLightManip::getBoundingBox(SoGetBoundingBoxAction * action)
277 {
278 int numindices;
279 const int * indices;
280 int lastchild;
281 SbVec3f center(0.0f, 0.0f, 0.0f);
282 int numcenters = 0;
283
284 if (action->getPathCode(numindices, indices) == SoAction::IN_PATH) {
285 lastchild = indices[numindices-1];
286 }
287 else {
288 lastchild = this->children->getLength() - 1;
289 }
290 for (int i = 0; i <= lastchild; i++) {
291 this->children->traverse(action, i, i);
292 if (action->isCenterSet()) {
293 center += action->getCenter();
294 numcenters++;
295 action->resetCenter();
296 }
297 }
298 SoPointLight::getBoundingBox(action);
299 if (action->isCenterSet()) {
300 center += action->getCenter();
301 numcenters++;
302 action->resetCenter();
303 }
304 if (numcenters != 0) {
305 action->setCenter(center / (float) numcenters, FALSE);
306 }
307 }
308
309 // Documented in superclass
310 void
getMatrix(SoGetMatrixAction * action)311 SoPointLightManip::getMatrix(SoGetMatrixAction * action)
312 {
313 int numindices;
314 const int * indices;
315 switch (action->getPathCode(numindices, indices)) {
316 case SoAction::NO_PATH:
317 case SoAction::BELOW_PATH:
318 break;
319 case SoAction::IN_PATH:
320 this->children->traverseInPath(action, numindices, indices);
321 break;
322 case SoAction::OFF_PATH:
323 this->children->traverse(action);
324 break;
325 default:
326 assert(0 && "unknown path code");
327 break;
328 }
329 }
330
331 // Documented in superclass
332 void
handleEvent(SoHandleEventAction * action)333 SoPointLightManip::handleEvent(SoHandleEventAction * action)
334 {
335 SoPointLightManip::doAction(action);
336 SoPointLight::handleEvent(action);
337 }
338
339 // Documented in superclass
340 void
pick(SoPickAction * action)341 SoPointLightManip::pick(SoPickAction * action)
342 {
343 SoPointLightManip::doAction(action);
344 SoPointLight::pick(action);
345 }
346
347 // Documented in superclass
348 void
search(SoSearchAction * action)349 SoPointLightManip::search(SoSearchAction * action)
350 {
351 inherited::search(action);
352 if (action->isFound()) return;
353 SoPointLightManip::doAction(action);
354 }
355
356 /*!
357 Returns the children of this node. This node only has the dragger
358 as a child.
359 */
360 SoChildList *
getChildren(void) const361 SoPointLightManip::getChildren(void) const
362 {
363 return this->children;
364 }
365
366 /*!
367 \COININTERNAL
368 */
369 void
valueChangedCB(void * m,SoDragger * dragger)370 SoPointLightManip::valueChangedCB(void * m, SoDragger * dragger)
371 {
372 SoPointLightManip * thisp = (SoPointLightManip *)m;
373
374 SbMatrix matrix = dragger->getMotionMatrix();
375 SbVec3f location = matrix[3];
376
377 thisp->attachSensors(FALSE);
378 if (thisp->location.getValue() != location) {
379 thisp->location = location;
380 }
381 thisp->attachSensors(TRUE);
382 }
383
384 /*!
385 \COININTERNAL
386 */
387 void
fieldSensorCB(void * m,SoSensor *)388 SoPointLightManip::fieldSensorCB(void * m, SoSensor *)
389 {
390 SoPointLightManip * thisp = (SoPointLightManip *)m;
391 SoDragger * dragger = thisp->getDragger();
392 if (dragger != NULL) {
393 SbVec3f location = thisp->location.getValue();
394 SbMatrix matrix = dragger->getMotionMatrix();
395 matrix[3][0] = location[0];
396 matrix[3][1] = location[1];
397 matrix[3][2] = location[2];
398 dragger->setMotionMatrix(matrix);
399
400 SoMaterial * material = (SoMaterial *)dragger->getPart("material", TRUE);
401 if (material->emissiveColor.getNum() != 1 ||
402 material->emissiveColor[0].getValue() != thisp->color.getValue()) {
403 // replace with new material since the material is reused between
404 // all draggers.
405 material = new SoMaterial;
406 material->diffuseColor = SbColor(0.0f, 0.0f, 0.0f);
407 material->emissiveColor = thisp->color.getValue();
408 dragger->setPart("material", material);
409 }
410 }
411 }
412
413 // Documented in superclass. Overridden to copy the internal dragger
414 // instance.
415 void
copyContents(const SoFieldContainer * fromfc,SbBool copyconnections)416 SoPointLightManip::copyContents(const SoFieldContainer * fromfc, SbBool copyconnections)
417 {
418 assert(fromfc->isOfType(SoPointLightManip::getClassTypeId()));
419 this->setDragger(((SoPointLightManip *)fromfc)->getDragger());
420 inherited::copyContents(fromfc, copyconnections);
421 }
422
423 /*!
424 \COININTERNAL
425 Copies field values.
426 */
427 void
transferFieldValues(const SoPointLight * from,SoPointLight * to)428 SoPointLightManip::transferFieldValues(const SoPointLight * from, SoPointLight * to)
429 {
430 to->location = from->location;
431 to->color = from->color;
432 }
433
434 void
attachSensors(const SbBool onoff)435 SoPointLightManip::attachSensors(const SbBool onoff)
436 {
437 if (onoff) {
438 this->locationFieldSensor->attach(&this->location);
439 this->colorFieldSensor->attach(&this->color);
440 }
441 else {
442 this->locationFieldSensor->detach();
443 this->colorFieldSensor->detach();
444 }
445 }
446
447 #endif // HAVE_MANIPULATORS
448