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_DRAGGERS
38 
39 /*!
40   \class SoDirectionalLightDragger SoDirectionalLightDragger.h Inventor/draggers/SoDirectionalLightDragger.h
41   \brief The SoDirectionalLightDragger class provides interactive geometry for manipulating a directional light source.
42 
43   \ingroup draggers
44 
45   \DRAGGER_DEFAULT_SCREENSHOT
46 
47   <center>
48   \image html directionallight.png "Screen Shot of Default Dragger"
49   </center>
50 
51   This dragger is well suited to use for setting up the fields of a
52   SoDirectionalLight node, as it provides geometry for the end-user to
53   interact with a directional vector.
54 
55   The image below is an action shot example, with the directional light being red
56   and the camera headlight turned right down.
57 
58   <center>
59   \image html directionallightdragger_actionshot.png "DirectionalLight Dragger Action Shot"
60   </center>
61 
62   For convenience, this dragger also by default contains interaction
63   geometry for placing the dragger itself. (SoDirectionalLight nodes
64   don't have a position field, so this was strictly not needed.)
65 
66   The Coin library also includes a manipulator class,
67   SoDirectionalLightManip, which wraps the functionality provided by
68   this class inside the necessary mechanisms for connecting it to
69   SoDirectionalLight node instances in a scenegraph.
70 
71   \sa SoDirectionalLightManip
72 */
73 
74 #include <Inventor/draggers/SoDirectionalLightDragger.h>
75 
76 #include <cstring>
77 
78 #include <Inventor/draggers/SoDragPointDragger.h>
79 #include <Inventor/draggers/SoRotateSphericalDragger.h>
80 #include <Inventor/nodes/SoMaterial.h>
81 #include <Inventor/nodes/SoRotation.h>
82 #include <Inventor/nodes/SoSeparator.h>
83 #include <Inventor/sensors/SoFieldSensor.h>
84 
85 #include <data/draggerDefaults/directionalLightDragger.h>
86 
87 #include "nodekits/SoSubKitP.h"
88 #include "SbBasicP.h"
89 
90 /*!
91   \var SoSFRotation SoDirectionalLightDragger::rotation
92 
93   This field is continuously updated to contain the rotation of the
94   current direction vector. The application programmer will typically
95   connect this to the rotation field of a SoDirectionalLight node
96   (unless using the SoDirectionalLightManip class, where this is taken
97   care of automatically).
98 
99   It may also of course be connected to any other rotation field
100   controlling the direction of scenegraph geometry, it does not have
101   to part of a SoDirectionalLight node specifically.
102 */
103 /*!
104   \var SoSFVec3f SoDirectionalLightDragger::translation
105 
106   Continuously updated to contain the current translation from the
107   dragger's local origo position.
108 
109   This field is not used by the SoDirectionalLightManip, but may be of
110   interest for the application programmer wanting to use the
111   SoDirectionalLightDragger outside the context of controlling a
112   directional light node.
113 */
114 
115 /*!
116   \var SoFieldSensor * SoDirectionalLightDragger::rotFieldSensor
117   \COININTERNAL
118 */
119 /*!
120   \var SoFieldSensor * SoDirectionalLightDragger::translFieldSensor
121   \COININTERNAL
122 */
123 
124 class SoDirectionalLightDraggerP {
125 public:
126 };
127 
128 SO_KIT_SOURCE(SoDirectionalLightDragger);
129 
130 
131 // Doc in superclass.
132 void
initClass(void)133 SoDirectionalLightDragger::initClass(void)
134 {
135   SO_KIT_INTERNAL_INIT_CLASS(SoDirectionalLightDragger, SO_FROM_INVENTOR_1);
136 }
137 
138 // FIXME: document which parts need to be present in the geometry
139 // scenegraph, and what role they play in the dragger. 20010913 mortene.
140 /*!
141   \DRAGGER_CONSTRUCTOR
142 
143   \NODEKIT_PRE_DIAGRAM
144 
145   \verbatim
146   CLASS SoDirectionalLightDragger
147   -->"this"
148         "callbackList"
149         "topSeparator"
150            "motionMatrix"
151   -->      "material"
152   -->      "translatorSep"
153   -->         "translatorRotInv"
154   -->         "translator"
155   -->      "rotator"
156            "geomSeparator"
157   \endverbatim
158 
159   \NODEKIT_POST_DIAGRAM
160 
161 
162   \NODEKIT_PRE_TABLE
163 
164   \verbatim
165   CLASS SoDirectionalLightDragger
166   PVT   "this",  SoDirectionalLightDragger  ---
167         "callbackList",  SoNodeKitListPart [ SoCallback, SoEventCallback ]
168   PVT   "topSeparator",  SoSeparator  ---
169   PVT   "motionMatrix",  SoMatrixTransform  ---
170         "material",  SoMaterial  ---
171   PVT   "translatorSep",  SoSeparator  ---
172         "translatorRotInv",  SoRotation  ---
173         "translator",  SoDragPointDragger  ---
174         "rotator",  SoRotateSphericalDragger  ---
175   PVT   "geomSeparator",  SoSeparator  ---
176   \endverbatim
177 
178   \NODEKIT_POST_TABLE
179 */
SoDirectionalLightDragger(void)180 SoDirectionalLightDragger::SoDirectionalLightDragger(void)
181 {
182   SO_KIT_INTERNAL_CONSTRUCTOR(SoDirectionalLightDragger);
183 
184   SO_KIT_ADD_CATALOG_ENTRY(material, SoMaterial, TRUE, topSeparator, translatorSep, TRUE);
185   SO_KIT_ADD_CATALOG_ENTRY(rotator, SoRotateSphericalDragger, TRUE, topSeparator, geomSeparator, TRUE);
186   SO_KIT_ADD_CATALOG_ENTRY(translator, SoDragPointDragger, TRUE, translatorSep, "", TRUE);
187   SO_KIT_ADD_CATALOG_ENTRY(translatorRotInv, SoRotation, TRUE, translatorSep, translator, TRUE);
188   SO_KIT_ADD_CATALOG_ENTRY(translatorSep, SoSeparator, TRUE, topSeparator, rotator, FALSE);
189 
190   if (SO_KIT_IS_FIRST_INSTANCE()) {
191     SoInteractionKit::readDefaultParts("directionalLightDragger.iv",
192                                        DIRECTIONALLIGHTDRAGGER_draggergeometry,
193                                        static_cast<int>(strlen(DIRECTIONALLIGHTDRAGGER_draggergeometry)));
194   }
195 
196   SO_KIT_ADD_FIELD(rotation, (SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f)));
197   SO_KIT_ADD_FIELD(translation, (0.0f, 0.0f, 0.0f));
198   SO_KIT_INIT_INSTANCE();
199 
200   SoDragger *pdragger = SO_GET_ANY_PART(this, "translator", SoDragPointDragger);
201   assert(pdragger);
202   SoDragger *sdragger = SO_GET_ANY_PART(this, "rotator", SoDragPointDragger);
203   assert(sdragger);
204 
205   this->setPartAsDefault("material", "directionalLightOverallMaterial");
206 
207   this->addValueChangedCallback(SoDirectionalLightDragger::valueChangedCB);
208 
209   this->rotFieldSensor = new SoFieldSensor(SoDirectionalLightDragger::fieldSensorCB, this);
210   this->rotFieldSensor->setPriority(0);
211   this->translFieldSensor = new SoFieldSensor(SoDirectionalLightDragger::fieldSensorCB, this);
212   this->translFieldSensor->setPriority(0);
213 
214   this->setUpConnections(TRUE, TRUE);
215 
216   // create this part to avoid changes in the scene graph while traversing it
217   (void) SO_GET_ANY_PART(this, "translatorRotInv", SoRotation);
218 
219   this->translatorSep.setDefault(TRUE);
220 }
221 
222 /*!
223   Protected destructor.
224 
225   (Dragger classes are derived from SoBase, so they are reference
226   counted and automatically destroyed when their reference count goes
227   to 0.)
228  */
~SoDirectionalLightDragger()229 SoDirectionalLightDragger::~SoDirectionalLightDragger()
230 {
231   delete this->translFieldSensor;
232   delete this->rotFieldSensor;
233 }
234 
235 // doc in superclass
236 SbBool
setUpConnections(SbBool onoff,SbBool doitalways)237 SoDirectionalLightDragger::setUpConnections(SbBool onoff, SbBool doitalways)
238 {
239   if (!doitalways && this->connectionsSetUp == onoff) return onoff;
240 
241   if (onoff) {
242     inherited::setUpConnections(onoff, doitalways);
243     SoDragger * therotator = coin_assert_cast<SoDragger *>(this->getAnyPart("rotator", FALSE));
244     therotator->setPartAsDefault("rotator", "directionalLightRotatorRotator");
245     therotator->setPartAsDefault("rotatorActive",
246                               "directionalLightRotatorRotatorActive");
247     therotator->setPartAsDefault("feedback",
248                               "directionalLightRotatorFeedback");
249     therotator->setPartAsDefault("feedbackActive",
250                               "directionalLightRotatorFeedbackActive");
251 
252     SoDragger *thetranslator = coin_assert_cast<SoDragger *>(this->getAnyPart("translator", FALSE));
253     thetranslator->setPartAsDefault("yzTranslator.translator",
254                                  "directionalLightTranslatorPlaneTranslator");
255     thetranslator->setPartAsDefault("xzTranslator.translator",
256                                  "directionalLightTranslatorPlaneTranslator");
257     thetranslator->setPartAsDefault("xyTranslator.translator",
258                                  "directionalLightTranslatorPlaneTranslator");
259     thetranslator->setPartAsDefault("yzTranslator.translatorActive",
260                                  "directionalLightTranslatorPlaneTranslatorActive");
261     thetranslator->setPartAsDefault("xzTranslator.translatorActive",
262                                  "directionalLightTranslatorPlaneTranslatorActive");
263     thetranslator->setPartAsDefault("xyTranslator.translatorActive",
264                                  "directionalLightTranslatorPlaneTranslatorActive");
265     thetranslator->setPartAsDefault("xTranslator.translator",
266                                  "directionalLightTranslatorLineTranslator");
267     thetranslator->setPartAsDefault("yTranslator.translator",
268                                  "directionalLightTranslatorLineTranslator");
269     thetranslator->setPartAsDefault("zTranslator.translator",
270                                  "directionalLightTranslatorLineTranslator");
271     thetranslator->setPartAsDefault("xTranslator.translatorActive",
272                                  "directionalLightTranslatorLineTranslatorActive");
273     thetranslator->setPartAsDefault("yTranslator.translatorActive",
274                                  "directionalLightTranslatorLineTranslatorActive");
275     thetranslator->setPartAsDefault("zTranslator.translatorActive",
276                                  "directionalLightTranslatorLineTranslatorActive");
277 
278     this->registerChildDragger(therotator);
279     this->registerChildDragger(thetranslator);
280 
281     if (this->translFieldSensor->getAttachedField() != &this->translation)
282       this->translFieldSensor->attach(&this->translation);
283     if (this->rotFieldSensor->getAttachedField() != &this->rotation)
284       this->rotFieldSensor->attach(&this->rotation);
285   }
286   else {
287     SoDragger * thetranslator = coin_assert_cast<SoDragger *>(this->getAnyPart("translator", FALSE));
288     this->unregisterChildDragger(thetranslator);
289     SoDragger * therotator = coin_assert_cast<SoDragger *>(this->getAnyPart("rotator", FALSE));
290     this->unregisterChildDragger(therotator);
291 
292     if (this->rotFieldSensor->getAttachedField() != NULL)
293       this->rotFieldSensor->detach();
294     if (this->translFieldSensor->getAttachedField() != NULL)
295       this->translFieldSensor->detach();
296 
297     inherited::setUpConnections(onoff, doitalways);
298   }
299   return !(this->connectionsSetUp = onoff);
300 }
301 
302 // doc in superclass
303 void
setDefaultOnNonWritingFields(void)304 SoDirectionalLightDragger::setDefaultOnNonWritingFields(void)
305 {
306   this->translator.setDefault(TRUE);
307   this->rotator.setDefault(TRUE);
308   this->translatorRotInv.setDefault(TRUE);
309 
310   inherited::setDefaultOnNonWritingFields();
311 }
312 
313 /*! \COININTERNAL */
314 void
fieldSensorCB(void * d,SoSensor *)315 SoDirectionalLightDragger::fieldSensorCB(void * d, SoSensor *)
316 {
317   SoDirectionalLightDragger * thisp = static_cast<SoDirectionalLightDragger *>(d);
318   SbMatrix matrix = thisp->getMotionMatrix();
319   thisp->workFieldsIntoTransform(matrix);
320   thisp->setMotionMatrix(matrix);
321 }
322 
323 /*! \COININTERNAL */
324 void
valueChangedCB(void *,SoDragger * d)325 SoDirectionalLightDragger::valueChangedCB(void *, SoDragger * d)
326 {
327   SoDirectionalLightDragger *thisp = static_cast<SoDirectionalLightDragger *>(d);
328   SbMatrix matrix = thisp->getMotionMatrix();
329   SbVec3f trans, scale;
330   SbRotation rot, scaleOrient;
331   matrix.getTransform(trans, rot, scale, scaleOrient);
332 
333   thisp->translFieldSensor->detach();
334   if (thisp->translation.getValue() != trans)
335     thisp->translation = trans;
336   thisp->translFieldSensor->attach(&thisp->translation);
337 
338   thisp->rotFieldSensor->detach();
339   if (thisp->rotation.getValue() != rot)
340     thisp->rotation = rot;
341   thisp->rotFieldSensor->attach(&thisp->rotation);
342 
343   SoRotation *invRot = SO_GET_ANY_PART(thisp, "translatorRotInv", SoRotation);
344   invRot->rotation = rot.inverse();
345 }
346 
347 #endif // HAVE_DRAGGERS
348