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