1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 //
15 // OpenFlight� loader for OpenSceneGraph
16 //
17 //  Copyright (C) 2005-2007  Brede Johansen
18 //
19 
20 #include <osgSim/MultiSwitch>
21 #include <osgSim/LightPointSystem>
22 #include <osgSim/LightPointNode>
23 #include <osg/Texture2D>
24 #include "Registry.h"
25 #include "Document.h"
26 #include "RecordInputStream.h"
27 
28 using namespace flt;
29 
30 /** LightPoint
31 */
32 class LightPoint : public PrimaryRecord
33 {
34     enum Directionality
35     {
36         OMNIDIRECTIONAL = 0,
37         UNIDIRECTIONAL = 1,
38         BIDIRECTIONAL = 2
39     };
40 
41     // flags
42     enum Flags
43     {
44                                                 // bit 0 = reserved
45         NO_BACK_COLOR    = 0x80000000u >> 1,        // bit 1 = no back color
46                                                 // bit 2 = reserved
47         CALLIGRAPHIC    = 0x80000000u >> 3,        // bit 3 = calligraphic proximity occulting
48         REFLECTIVE        = 0x80000000u >> 4,        // bit 4 = reflective, non-emissive point
49                                                 // bit 5-7 = randomize intensity
50                                                 //   0 = never
51                                                 //     1 = low
52                                                 //   2 = medium
53                                                 //   3 = high
54         PERSPECTIVE        = 0x80000000u >> 8,        // bit 8 = perspective mode
55         FLASHING        = 0x80000000u >> 9,        // bit 9 = flashing
56         ROTATING        = 0x80000000u >> 10,    // bit 10 = rotating
57         ROTATE_CC        = 0x80000000u >> 11,    // bit 11 = rotate counter clockwise
58                                                 // bit 12 = reserved
59                                                 // bit 13-14 = quality
60                                                 //   0 = low
61                                                 //     1 = medium
62                                                 //   2 = high
63                                                 //   3 = undefined
64         VISIBLE_DAY        = 0x80000000u >> 15,    // bit 15 = visible during day
65         VISIBLE_DUSK    = 0x80000000u >> 16,    // bit 16 = visible during dusk
66         VISIBLE_NIGHT    = 0x80000000u >> 17        // bit 17 = visible during night
67                                                 // bit 18-31 = spare
68     };
69 
70 
71     int16   _material;
72     int16   _feature;
73     osg::Vec4f _backColor;
74     int32   _displayMode;
75     float32 _intensityFront;
76     float32 _intensityBack;
77     float32 _minDefocus;
78     float32 _maxDefocus;
79     int32   _fadeMode;
80     int32   _fogPunchMode;
81     int32   _directionalMode;
82     int32   _rangeMode;
83     float32 _minPixelSize;
84     float32 _maxPixelSize;
85     float32 _actualPixelSize;
86     float32 _transparentFalloff;
87     float32 _transparentFalloffExponent;
88     float32 _transparentFalloffScalar;
89     float32 _transparentFalloffClamp;
90     float32 _fog;
91     float32 _sizeDifferenceThreshold;
92     int32   _directionality;
93     float32 _lobeHorizontal;
94     float32 _lobeVertical;
95     float32 _lobeRoll;
96     float32 _falloff;
97     float32 _ambientIntensity;
98     float32 _animationPeriod;
99     float32 _animationPhaseDelay;
100     float32 _animationPeriodEnable;
101     float32 _significance;
102     int32   _drawOrder;
103     uint32  _flags;
104     osg::Vec3f _animationAxis;
105 
106     osg::ref_ptr<osgSim::LightPointNode> _lpn;
107 
108 public:
109 
110     LightPoint() {}
111 
112     META_Record(LightPoint)
113 
114     META_setID(_lpn)
115     META_setComment(_lpn)
116     META_dispose(_lpn)
117 
118     // Add lightpoint, add two if bidirectional.
119     virtual void addVertex(Vertex& vertex)
120     {
121         osgSim::LightPoint lp;
122         lp._position = vertex._coord;
123         lp._radius = 0.5f * _actualPixelSize;
124         lp._intensity = _intensityFront;
125 
126         // color
127         lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1);
128 
129         // sector
130         bool directional = (_directionality==UNIDIRECTIONAL) || (_directionality==BIDIRECTIONAL);
131         if (directional && vertex.validNormal())
132         {
133             lp._sector = new osgSim::DirectionalSector(
134                 vertex._normal,
135                 osg::DegreesToRadians(_lobeHorizontal),
136                 osg::DegreesToRadians(_lobeVertical),
137                 osg::DegreesToRadians(_lobeRoll));
138         }
139 
140         // if the flashing or rotating bit is set in the flags, add a blink sequence
141         if ((_flags & FLASHING) || (_flags & ROTATING))
142         {
143             lp._blinkSequence = new osgSim::BlinkSequence();
144             if (lp._blinkSequence.valid())
145             {
146                 lp._blinkSequence->setDataVariance(osg::Object::DYNAMIC);
147                 lp._blinkSequence->setPhaseShift(_animationPhaseDelay);
148                 lp._blinkSequence->addPulse(_animationPeriod - _animationPeriodEnable,
149                     osg::Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
150                 lp._blinkSequence->addPulse(_animationPeriodEnable, lp._color);
151             }
152         }
153 
154         _lpn->addLightPoint(lp);
155 
156         // Create a new lightpoint if bi-directional.
157         if ((_directionality==BIDIRECTIONAL) && vertex.validNormal())
158         {
159             // back intensity
160             lp._intensity = _intensityBack;
161 
162             // back color
163             if (!(_flags & NO_BACK_COLOR))
164                 lp._color = _backColor;
165 
166             // back sector
167             lp._sector = new osgSim::DirectionalSector(
168                 -vertex._normal,
169                 osg::DegreesToRadians(_lobeHorizontal),
170                 osg::DegreesToRadians(_lobeVertical),
171                 osg::DegreesToRadians(_lobeRoll));
172 
173             _lpn->addLightPoint(lp);
174         }
175     }
176 
177 protected:
178 
179     virtual ~LightPoint() {}
180 
181     virtual void readRecord(RecordInputStream& in, Document& document)
182     {
183         std::string id = in.readString(8);
184         _material = in.readInt16();
185         _feature = in.readInt16();
186 
187         int32 backColorIndex = in.readInt32();
188 
189         _backColor = document.getColorPool() ?
190                             document.getColorPool()->getColor(backColorIndex) :
191                             osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
192 
193         _displayMode = in.readInt32();
194         _intensityFront = in.readFloat32();
195         _intensityBack = in.readFloat32();
196         _minDefocus = in.readFloat32();
197         _maxDefocus = in.readFloat32();
198         _fadeMode = in.readInt32();
199         _fogPunchMode = in.readInt32();
200         _directionalMode = in.readInt32();
201         _rangeMode = in.readInt32();
202         _minPixelSize = in.readFloat32(); // * document.unitScale();
203         _maxPixelSize = in.readFloat32(); // * document.unitScale();
204         _actualPixelSize = in.readFloat32(); // * document.unitScale();
205         _transparentFalloff = in.readFloat32();
206         _transparentFalloffExponent = in.readFloat32();
207         _transparentFalloffScalar = in.readFloat32();
208         _transparentFalloffClamp = in.readFloat32();
209         _fog = in.readFloat32();
210         in.forward(4);
211         _sizeDifferenceThreshold = in.readFloat32();
212         _directionality = in.readInt32();
213         _lobeHorizontal = in.readFloat32();
214         _lobeVertical = in.readFloat32();
215         _lobeRoll = in.readFloat32();
216         _falloff = in.readFloat32();
217         _ambientIntensity = in.readFloat32();
218         _animationPeriod = in.readFloat32();
219         _animationPhaseDelay = in.readFloat32();
220         _animationPeriodEnable = in.readFloat32();
221         _significance = in.readFloat32();
222         _drawOrder = in.readInt32();
223         _flags = in.readUInt32(0);
224         _animationAxis = in.readVec3f();
225 
226         _lpn = new osgSim::LightPointNode;
227         _lpn->setName(id);
228         _lpn->setMinPixelSize(_minPixelSize);
229         _lpn->setMaxPixelSize(_maxPixelSize);
230 
231         // Add to parent
232         if (_parent.valid())
233             _parent->addChild(*_lpn);
234     }
235 };
236 
237 REGISTER_FLTRECORD(LightPoint, LIGHT_POINT_OP)
238 
239 
240 
241 /** IndexedLightPoint
242 */
243 class IndexedLightPoint : public PrimaryRecord
244 {
245     enum Directionality
246     {
247         OMNIDIRECTIONAL = 0,
248         UNIDIRECTIONAL = 1,
249         BIDIRECTIONAL = 2
250     };
251 
252     // flags
253     static const unsigned int NO_BACK_COLOR_BIT = 0x80000000u >> 1;
254 
255     osg::ref_ptr<osgSim::LightPointNode> _lpn;
256     osg::ref_ptr<LPAppearance> _appearance;
257     osg::ref_ptr<LPAnimation> _animation;
258 
259 public:
260 
261     IndexedLightPoint() {}
262 
263     META_Record(IndexedLightPoint)
264 
265     META_setID(_lpn)
266     META_setComment(_lpn)
267     META_dispose(_lpn)
268 
269     // Add lightpoint, add two if bidirectional.
270     virtual void addVertex(Vertex& vertex)
271     {
272         osgSim::LightPoint lp;
273 
274         if (_appearance.valid())
275         {
276             lp._position = vertex._coord;
277             lp._radius = 0.5f * _appearance->actualPixelSize;
278             lp._intensity = _appearance->intensityFront;
279 
280             // color
281             lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1);
282 
283             // sector
284             bool directional = (_appearance->directionality==UNIDIRECTIONAL) || (_appearance->directionality==BIDIRECTIONAL);
285             if (directional && vertex.validNormal())
286             {
287                 lp._sector = new osgSim::DirectionalSector(
288                     vertex._normal,
289                     osg::DegreesToRadians(_appearance->horizontalLobeAngle),
290                     osg::DegreesToRadians(_appearance->verticalLobeAngle),
291                     osg::DegreesToRadians(_appearance->lobeRollAngle));
292             }
293 
294             // Blink sequence
295             if (_animation.valid())
296             {
297                 osgSim::BlinkSequence* blinkSequence = new osgSim::BlinkSequence;
298                 blinkSequence->setName(_animation->name);
299 
300                 switch (_animation->animationType)
301                 {
302                 case LPAnimation::ROTATING:
303                 case LPAnimation::STROBE:
304                     blinkSequence->setPhaseShift(_animation->animationPhaseDelay);
305                     blinkSequence->addPulse(_animation->animationPeriod-_animation->animationEnabledPeriod, osg::Vec4(0,0,0,0));
306                     blinkSequence->addPulse(_animation->animationEnabledPeriod, lp._color);
307                     break;
308 
309                 case LPAnimation::MORSE_CODE:
310                     // todo
311                     //blinkSequence->addPulse(double length,lp._color);
312                     break;
313 
314                 case LPAnimation::FLASHING_SEQUENCE:
315                     {
316                         blinkSequence->setPhaseShift(_animation->animationPhaseDelay);
317 
318                         for (LPAnimation::PulseArray::iterator itr=_animation->sequence.begin();
319                             itr!=_animation->sequence.end();
320                             ++itr)
321                         {
322                             double duration = itr->duration;
323 
324                             osg::Vec4 color;
325                             switch (itr->state)
326                             {
327                             case LPAnimation::ON:
328                                 color = lp._color;
329                                 break;
330                             case LPAnimation::OFF:
331                                 color = osg::Vec4(0,0,0,0);
332                                 break;
333                             case LPAnimation::COLOR_CHANGE:
334                                 color = itr->color;
335                                 break;
336                             }
337 
338                             blinkSequence->addPulse(duration, color);
339                         }
340                     }
341                     break;
342                 }
343 
344                 lp._blinkSequence = blinkSequence;
345             }
346 
347             _lpn->addLightPoint(lp);
348 
349             // Create a new lightpoint if bi-directional.
350             if ((_appearance->directionality==BIDIRECTIONAL) && vertex.validNormal())
351             {
352                 // back intensity
353                 lp._intensity = _appearance->intensityBack;
354 
355                 // back color
356                 if (!(_appearance->flags & NO_BACK_COLOR_BIT))
357                     lp._color = _appearance->backColor;
358 
359                 // back sector
360                 lp._sector = new osgSim::DirectionalSector(
361                     -vertex._normal,
362                     osg::DegreesToRadians(_appearance->horizontalLobeAngle),
363                     osg::DegreesToRadians(_appearance->verticalLobeAngle),
364                     osg::DegreesToRadians(_appearance->lobeRollAngle));
365 
366                 _lpn->addLightPoint(lp);
367             }
368         }
369     }
370 
371 
372 protected:
373 
374     virtual ~IndexedLightPoint() {}
375 
376     virtual void readRecord(RecordInputStream& in, Document& document)
377     {
378         std::string id = in.readString(8);
379         int32 appearanceIndex = in.readInt32();
380         int32 animationIndex = in.readInt32();
381         /*int32 drawOrder =*/ in.readInt32();           // for calligraphic lights
382 
383         LightPointAppearancePool* lpAppearancePool = document.getOrCreateLightPointAppearancePool();
384         _appearance = lpAppearancePool->get(appearanceIndex);
385 
386         LightPointAnimationPool* lpAnimationPool = document.getOrCreateLightPointAnimationPool();
387         _animation = lpAnimationPool->get(animationIndex);
388 
389         _lpn = new osgSim::LightPointNode;
390         _lpn->setName(id);
391 
392         if (_appearance.valid())
393         {
394             _lpn->setMinPixelSize(_appearance->minPixelSize);
395             _lpn->setMaxPixelSize(_appearance->maxPixelSize);
396 
397             if (_appearance->texturePatternIndex != -1)
398             {
399                 // Use point sprites for light points.
400                 _lpn->setPointSprite();
401 
402                 TexturePool* tp = document.getOrCreateTexturePool();
403                 osg::StateSet* textureStateSet = tp->get(_appearance->texturePatternIndex);
404                 if (textureStateSet)
405                 {
406                     // Merge face stateset with texture stateset
407                     osg::StateSet* stateset = _lpn->getOrCreateStateSet();
408                     stateset->merge(*textureStateSet);
409                 }
410             }
411         }
412 
413         // Add to parent
414         if (_parent.valid())
415             _parent->addChild(*_lpn);
416 
417     }
418 };
419 
420 REGISTER_FLTRECORD(IndexedLightPoint, INDEXED_LIGHT_POINT_OP)
421 
422 
423 
424 /** LightPointSystem
425 */
426 class LightPointSystem : public PrimaryRecord
427 {
428     float32 _intensity;
429     int32 _animationState;
430     int32  _flags;
431 
432     osg::ref_ptr<osgSim::MultiSwitch> _switch;
433     osg::ref_ptr<osgSim::LightPointSystem> _lps;
434 
435 public:
436 
437     LightPointSystem():
438         _intensity(1.0f),
439         _animationState(0),
440         _flags(0)
441     {}
442 
443     META_Record(LightPointSystem)
444     META_addChild(_switch)
445 
446 protected:
447 
448     virtual ~LightPointSystem() {}
449 
450     virtual void readRecord(RecordInputStream& in, Document& document)
451     {
452         std::string id = in.readString(8);
453 
454         _intensity = in.readFloat32();
455         _animationState = in.readInt32(0);
456         _flags = in.readInt32(0);
457 
458         _switch = new osgSim::MultiSwitch;
459         _lps = new osgSim::LightPointSystem;
460 
461         _switch->setName(id);
462         _lps->setName(id);
463         _lps->setIntensity(_intensity);
464 
465         switch (_animationState)
466         {
467             // Note that OpenFlight 15.8 spec says 0 means on and 1 means off.
468             // However, if animation is set on in Creator, it stores a 1, and
469             // a zero is stored for off! So, for now, we ignore the spec...
470             case 0:
471                 _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_OFF );
472                 break;
473             default:
474             case 1:
475                 _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_ON );
476                 break;
477             case 2:
478                 _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_RANDOM );
479                 break;
480         }
481 
482         if (_parent.valid())
483             _parent->addChild(*((osg::Group*)_switch.get()));
484     }
485 
486     virtual void dispose(Document& document)
487     {
488         if (!_switch.valid()) return;
489 
490         // Insert transform(s)
491         if (_matrix.valid())
492         {
493             insertMatrixTransform(*_switch,*_matrix,_numberOfReplications);
494         }
495 
496         // Set default sets: 0 for all off, 1 for all on
497         _switch->setAllChildrenOff( 0 );
498         _switch->setAllChildrenOn( 1 );
499 
500         // set initial on/off state
501         unsigned int initialSet = ( (_flags & 0x80000000) != 0 ) ? 1 : 0;
502         _switch->setActiveSwitchSet( initialSet );
503 
504         for (unsigned int i = 0; i < _switch->getNumChildren(); i++)
505         {
506             osg::Node* child = _switch->getChild(i);
507             if (osgSim::LightPointNode* lpn = dynamic_cast<osgSim::LightPointNode*>(child))
508                 lpn->setLightPointSystem(_lps.get());
509         }
510     }
511 };
512 
513 REGISTER_FLTRECORD(LightPointSystem, LIGHT_POINT_SYSTEM_OP)
514 
515 
516