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 
LightPoint()110     LightPoint():
111         _material(0),
112         _feature(0),
113         _backColor(1.0f,1.0f,1.0f,1.0f),
114         _displayMode(0),
115         _intensityFront(0.0f),
116         _intensityBack(0.0f),
117         _minDefocus(0.0f),
118         _maxDefocus(0.0f),
119         _fadeMode(0),
120         _fogPunchMode(0),
121         _directionalMode(0),
122         _rangeMode(0),
123         _minPixelSize(0.0f),
124         _maxPixelSize(0.0f),
125         _actualPixelSize(0.0f),
126         _transparentFalloff(0.0f),
127         _transparentFalloffExponent(0.0f),
128         _transparentFalloffScalar(0.0f),
129         _transparentFalloffClamp(0.0f),
130         _fog(0.0f),
131         _sizeDifferenceThreshold(0.0f),
132         _directionality(0),
133         _lobeHorizontal(0.0f),
134         _lobeVertical(0.0f),
135         _lobeRoll(0.0f),
136         _falloff(0.0f),
137         _ambientIntensity(0.0f),
138         _animationPeriod(0.0f),
139         _animationPhaseDelay(0.0f),
140         _animationPeriodEnable(0.0f),
141         _significance(0.0f),
142         _drawOrder(0),
143         _flags(0),
144         _animationAxis(0.0f,0.0f,1.0f)
145     {}
146 
147     META_Record(LightPoint)
148 
META_setID(_lpn)149     META_setID(_lpn)
150     META_setComment(_lpn)
151     META_dispose(_lpn)
152 
153     // Add lightpoint, add two if bidirectional.
154     virtual void addVertex(Vertex& vertex)
155     {
156         osgSim::LightPoint lp;
157         lp._position = vertex._coord;
158         lp._radius = 0.5f * _actualPixelSize;
159         lp._intensity = _intensityFront;
160 
161         // color
162         lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1);
163 
164         // sector
165         bool directional = (_directionality==UNIDIRECTIONAL) || (_directionality==BIDIRECTIONAL);
166         if (directional && vertex.validNormal())
167         {
168             lp._sector = new osgSim::DirectionalSector(
169                 vertex._normal,
170                 osg::DegreesToRadians(_lobeHorizontal),
171                 osg::DegreesToRadians(_lobeVertical),
172                 osg::DegreesToRadians(_lobeRoll));
173         }
174 
175         // if the flashing or rotating bit is set in the flags, add a blink sequence
176         if ((_flags & FLASHING) || (_flags & ROTATING))
177         {
178             lp._blinkSequence = new osgSim::BlinkSequence();
179             if (lp._blinkSequence.valid())
180             {
181                 lp._blinkSequence->setDataVariance(osg::Object::DYNAMIC);
182                 lp._blinkSequence->setPhaseShift(_animationPhaseDelay);
183                 lp._blinkSequence->addPulse(_animationPeriod - _animationPeriodEnable,
184                     osg::Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
185                 lp._blinkSequence->addPulse(_animationPeriodEnable, lp._color);
186             }
187         }
188 
189         _lpn->addLightPoint(lp);
190 
191         // Create a new lightpoint if bi-directional.
192         if ((_directionality==BIDIRECTIONAL) && vertex.validNormal())
193         {
194             // back intensity
195             lp._intensity = _intensityBack;
196 
197             // back color
198             if (!(_flags & NO_BACK_COLOR))
199                 lp._color = _backColor;
200 
201             // back sector
202             lp._sector = new osgSim::DirectionalSector(
203                 -vertex._normal,
204                 osg::DegreesToRadians(_lobeHorizontal),
205                 osg::DegreesToRadians(_lobeVertical),
206                 osg::DegreesToRadians(_lobeRoll));
207 
208             _lpn->addLightPoint(lp);
209         }
210     }
211 
212 protected:
213 
~LightPoint()214     virtual ~LightPoint() {}
215 
readRecord(RecordInputStream & in,Document & document)216     virtual void readRecord(RecordInputStream& in, Document& document)
217     {
218         std::string id = in.readString(8);
219         _material = in.readInt16();
220         _feature = in.readInt16();
221 
222         int32 backColorIndex = in.readInt32();
223 
224         _backColor = document.getColorPool() ?
225                             document.getColorPool()->getColor(backColorIndex) :
226                             osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
227 
228         _displayMode = in.readInt32();
229         _intensityFront = in.readFloat32();
230         _intensityBack = in.readFloat32();
231         _minDefocus = in.readFloat32();
232         _maxDefocus = in.readFloat32();
233         _fadeMode = in.readInt32();
234         _fogPunchMode = in.readInt32();
235         _directionalMode = in.readInt32();
236         _rangeMode = in.readInt32();
237         _minPixelSize = in.readFloat32(); // * document.unitScale();
238         _maxPixelSize = in.readFloat32(); // * document.unitScale();
239         _actualPixelSize = in.readFloat32(); // * document.unitScale();
240         _transparentFalloff = in.readFloat32();
241         _transparentFalloffExponent = in.readFloat32();
242         _transparentFalloffScalar = in.readFloat32();
243         _transparentFalloffClamp = in.readFloat32();
244         _fog = in.readFloat32();
245         in.forward(4);
246         _sizeDifferenceThreshold = in.readFloat32();
247         _directionality = in.readInt32();
248         _lobeHorizontal = in.readFloat32();
249         _lobeVertical = in.readFloat32();
250         _lobeRoll = in.readFloat32();
251         _falloff = in.readFloat32();
252         _ambientIntensity = in.readFloat32();
253         _animationPeriod = in.readFloat32();
254         _animationPhaseDelay = in.readFloat32();
255         _animationPeriodEnable = in.readFloat32();
256         _significance = in.readFloat32();
257         _drawOrder = in.readInt32();
258         _flags = in.readUInt32(0);
259         _animationAxis = in.readVec3f();
260 
261         _lpn = new osgSim::LightPointNode;
262         _lpn->setName(id);
263         _lpn->setMinPixelSize(_minPixelSize);
264         _lpn->setMaxPixelSize(_maxPixelSize);
265 
266         // Add to parent
267         if (_parent.valid())
268             _parent->addChild(*_lpn);
269     }
270 };
271 
272 REGISTER_FLTRECORD(LightPoint, LIGHT_POINT_OP)
273 
274 
275 
276 /** IndexedLightPoint
277 */
278 class IndexedLightPoint : public PrimaryRecord
279 {
280     enum Directionality
281     {
282         OMNIDIRECTIONAL = 0,
283         UNIDIRECTIONAL = 1,
284         BIDIRECTIONAL = 2
285     };
286 
287     // flags
288     static const unsigned int NO_BACK_COLOR_BIT = 0x80000000u >> 1;
289 
290     osg::ref_ptr<osgSim::LightPointNode> _lpn;
291     osg::ref_ptr<LPAppearance> _appearance;
292     osg::ref_ptr<LPAnimation> _animation;
293 
294 public:
295 
IndexedLightPoint()296     IndexedLightPoint() {}
297 
298     META_Record(IndexedLightPoint)
299 
META_setID(_lpn)300     META_setID(_lpn)
301     META_setComment(_lpn)
302     META_dispose(_lpn)
303 
304     // Add lightpoint, add two if bidirectional.
305     virtual void addVertex(Vertex& vertex)
306     {
307         osgSim::LightPoint lp;
308 
309         if (_appearance.valid())
310         {
311             lp._position = vertex._coord;
312             lp._radius = 0.5f * _appearance->actualPixelSize;
313             lp._intensity = _appearance->intensityFront;
314 
315             // color
316             lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1);
317 
318             // sector
319             bool directional = (_appearance->directionality==UNIDIRECTIONAL) || (_appearance->directionality==BIDIRECTIONAL);
320             if (directional && vertex.validNormal())
321             {
322                 lp._sector = new osgSim::DirectionalSector(
323                     vertex._normal,
324                     osg::DegreesToRadians(_appearance->horizontalLobeAngle),
325                     osg::DegreesToRadians(_appearance->verticalLobeAngle),
326                     osg::DegreesToRadians(_appearance->lobeRollAngle));
327             }
328 
329             // Blink sequence
330             if (_animation.valid())
331             {
332                 osgSim::BlinkSequence* blinkSequence = new osgSim::BlinkSequence;
333                 blinkSequence->setName(_animation->name);
334 
335                 switch (_animation->animationType)
336                 {
337                 case LPAnimation::ROTATING:
338                 case LPAnimation::STROBE:
339                     blinkSequence->setPhaseShift(_animation->animationPhaseDelay);
340                     blinkSequence->addPulse(_animation->animationPeriod-_animation->animationEnabledPeriod, osg::Vec4(0,0,0,0));
341                     blinkSequence->addPulse(_animation->animationEnabledPeriod, lp._color);
342                     break;
343 
344                 case LPAnimation::MORSE_CODE:
345                     // todo
346                     //blinkSequence->addPulse(double length,lp._color);
347                     break;
348 
349                 case LPAnimation::FLASHING_SEQUENCE:
350                     {
351                         blinkSequence->setPhaseShift(_animation->animationPhaseDelay);
352 
353                         for (LPAnimation::PulseArray::iterator itr=_animation->sequence.begin();
354                             itr!=_animation->sequence.end();
355                             ++itr)
356                         {
357                             double duration = itr->duration;
358 
359                             osg::Vec4 color;
360                             switch (itr->state)
361                             {
362                             case LPAnimation::ON:
363                                 color = lp._color;
364                                 break;
365                             case LPAnimation::OFF:
366                                 color = osg::Vec4(0,0,0,0);
367                                 break;
368                             case LPAnimation::COLOR_CHANGE:
369                                 color = itr->color;
370                                 break;
371                             }
372 
373                             blinkSequence->addPulse(duration, color);
374                         }
375                     }
376                     break;
377                 }
378 
379                 lp._blinkSequence = blinkSequence;
380             }
381 
382             _lpn->addLightPoint(lp);
383 
384             // Create a new lightpoint if bi-directional.
385             if ((_appearance->directionality==BIDIRECTIONAL) && vertex.validNormal())
386             {
387                 // back intensity
388                 lp._intensity = _appearance->intensityBack;
389 
390                 // back color
391                 if (!(_appearance->flags & NO_BACK_COLOR_BIT))
392                     lp._color = _appearance->backColor;
393 
394                 // back sector
395                 lp._sector = new osgSim::DirectionalSector(
396                     -vertex._normal,
397                     osg::DegreesToRadians(_appearance->horizontalLobeAngle),
398                     osg::DegreesToRadians(_appearance->verticalLobeAngle),
399                     osg::DegreesToRadians(_appearance->lobeRollAngle));
400 
401                 _lpn->addLightPoint(lp);
402             }
403         }
404     }
405 
406 
407 protected:
408 
~IndexedLightPoint()409     virtual ~IndexedLightPoint() {}
410 
readRecord(RecordInputStream & in,Document & document)411     virtual void readRecord(RecordInputStream& in, Document& document)
412     {
413         std::string id = in.readString(8);
414         int32 appearanceIndex = in.readInt32();
415         int32 animationIndex = in.readInt32();
416         /*int32 drawOrder =*/ in.readInt32();           // for calligraphic lights
417 
418         LightPointAppearancePool* lpAppearancePool = document.getOrCreateLightPointAppearancePool();
419         _appearance = lpAppearancePool->get(appearanceIndex);
420 
421         LightPointAnimationPool* lpAnimationPool = document.getOrCreateLightPointAnimationPool();
422         _animation = lpAnimationPool->get(animationIndex);
423 
424         _lpn = new osgSim::LightPointNode;
425         _lpn->setName(id);
426 
427         if (_appearance.valid())
428         {
429             _lpn->setMinPixelSize(_appearance->minPixelSize);
430             _lpn->setMaxPixelSize(_appearance->maxPixelSize);
431 
432             if (_appearance->texturePatternIndex != -1)
433             {
434                 // Use point sprites for light points.
435                 _lpn->setPointSprite();
436 
437                 TexturePool* tp = document.getOrCreateTexturePool();
438                 osg::StateSet* textureStateSet = tp->get(_appearance->texturePatternIndex);
439                 if (textureStateSet)
440                 {
441                     // Merge face stateset with texture stateset
442                     osg::StateSet* stateset = _lpn->getOrCreateStateSet();
443                     stateset->merge(*textureStateSet);
444                 }
445             }
446         }
447 
448         // Add to parent
449         if (_parent.valid())
450             _parent->addChild(*_lpn);
451 
452     }
453 };
454 
455 REGISTER_FLTRECORD(IndexedLightPoint, INDEXED_LIGHT_POINT_OP)
456 
457 
458 
459 /** LightPointSystem
460 */
461 class LightPointSystem : public PrimaryRecord
462 {
463     float32 _intensity;
464     int32 _animationState;
465     int32  _flags;
466 
467     osg::ref_ptr<osgSim::MultiSwitch> _switch;
468     osg::ref_ptr<osgSim::LightPointSystem> _lps;
469 
470 public:
471 
LightPointSystem()472     LightPointSystem():
473         _intensity(1.0f),
474         _animationState(0),
475         _flags(0)
476     {}
477 
478     META_Record(LightPointSystem)
479     META_addChild(_switch)
480 
481 protected:
482 
~LightPointSystem()483     virtual ~LightPointSystem() {}
484 
readRecord(RecordInputStream & in,Document &)485     virtual void readRecord(RecordInputStream& in, Document& /*document*/)
486     {
487         std::string id = in.readString(8);
488 
489         _intensity = in.readFloat32();
490         _animationState = in.readInt32(0);
491         _flags = in.readInt32(0);
492 
493         _switch = new osgSim::MultiSwitch;
494         _lps = new osgSim::LightPointSystem;
495 
496         _switch->setName(id);
497         _lps->setName(id);
498         _lps->setIntensity(_intensity);
499 
500         switch (_animationState)
501         {
502             // Note that OpenFlight 15.8 spec says 0 means on and 1 means off.
503             // However, if animation is set on in Creator, it stores a 1, and
504             // a zero is stored for off! So, for now, we ignore the spec...
505             case 0:
506                 _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_OFF );
507                 break;
508             default:
509             case 1:
510                 _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_ON );
511                 break;
512             case 2:
513                 _lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_RANDOM );
514                 break;
515         }
516 
517         if (_parent.valid())
518             _parent->addChild(*((osg::Group*)_switch.get()));
519     }
520 
dispose(Document &)521     virtual void dispose(Document& /*document*/)
522     {
523         if (!_switch.valid()) return;
524 
525         // Insert transform(s)
526         if (_matrix.valid())
527         {
528             insertMatrixTransform(*_switch,*_matrix,_numberOfReplications);
529         }
530 
531         // Set default sets: 0 for all off, 1 for all on
532         _switch->setAllChildrenOff( 0 );
533         _switch->setAllChildrenOn( 1 );
534 
535         // set initial on/off state
536         unsigned int initialSet = ( (_flags & 0x80000000) != 0 ) ? 1 : 0;
537         _switch->setActiveSwitchSet( initialSet );
538 
539         for (unsigned int i = 0; i < _switch->getNumChildren(); i++)
540         {
541             osg::Node* child = _switch->getChild(i);
542             if (osgSim::LightPointNode* lpn = dynamic_cast<osgSim::LightPointNode*>(child))
543                 lpn->setLightPointSystem(_lps.get());
544         }
545     }
546 };
547 
548 REGISTER_FLTRECORD(LightPointSystem, LIGHT_POINT_SYSTEM_OP)
549 
550 
551