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