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