Files
OpenSceneGraph/src/osgPlugins/flt/flt2osg.cpp
2004-11-22 23:54:45 +00:00

3250 lines
112 KiB
C++

// Modify ConvertFromFLT::setTexture to create a new osg::TexEnvCombiner in texture stateset to handle
// detail texture
// Julian Ortiz, June 18th 2003.
#include <stdio.h>
#include <string.h>
#include <osg/GL>
#include <osg/Group>
#include <osg/LOD>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osg/StateSet>
#include <osg/CullFace>
#include <osg/TexEnv>
#include <osg/TexEnvCombine>
#include <osg/TexGen>
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/Point>
#include <osg/Material>
#include <osg/PolygonOffset>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Billboard>
#include <osg/Texture2D>
#include <osg/LightSource>
#include <osg/Image>
#include <osg/Notify>
#include <osg/Sequence>
#include <osg/ShapeDrawable>
#include <osg/Quat>
#include <osgSim/MultiSwitch>
#include <osgSim/DOFTransform>
#include <osgSim/LightPointNode>
#include <osgSim/LightPointSystem>
#include <osgSim/Sector>
#include <osgSim/BlinkSequence>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include "opcodes.h"
#include "flt.h"
#include "flt2osg.h"
#include "FltFile.h"
#include "Registry.h"
#include "Record.h"
#include "HeaderRecord.h"
#include "ColorPaletteRecord.h"
#include "MaterialPaletteRecord.h"
#include "OldMaterialPaletteRecord.h"
#include "TexturePaletteRecord.h"
#include "LightPointPaletteRecords.h"
#include "VertexPoolRecords.h"
#include "OldVertexRecords.h"
#include "GroupRecord.h"
#include "LodRecord.h"
#include "DofRecord.h"
#include "SwitchRecord.h"
#include "ObjectRecord.h"
#include "FaceRecord.h"
#include "MeshRecord.h"
#include "MeshPrimitiveRecord.h"
#include "TransformationRecords.h"
#include "ExternalRecord.h"
#include "LightPointRecord.h"
#include "LightPointSystemRecord.h"
#include "Input.h"
#include "GeoSetBuilder.h"
#include "LongIDRecord.h"
#include "CommentRecord.h"
#include "InstanceRecords.h"
#include "LocalVertexPoolRecord.h"
#include "MultiTextureRecord.h"
#include "UVListRecord.h"
#include "LightSourceRecord.h"
#include "LightSourcePaletteRecord.h"
#include "AttrData.h"
#include "BSPRecord.h"
#include "FindExternalModelVisitor.h"
static int dprint = 0 ;
#define DPRINT if(dprint)fprintf
using namespace flt;
unsigned int mystrnlen(char *s, unsigned int maxLen)
{
for (unsigned int i = 0; i < maxLen; i++)
{
if (!s[i]) return i;
}
return maxLen;
}
ConvertFromFLT::ConvertFromFLT() :
_faceColor(1,1,1,1)
{
_diOpenFlightVersion = 0;
_diCurrentOffset = 0;
_wObjTransparency = 0;
_nSubfaceLevel = 0;
_unitScale = 1.0;
_useTextureAlphaForTranspancyBinning = true;
_bHdrRgbMode = false;
_currentLocalVertexPool = 0;
_doUnitsConversion = true;
}
ConvertFromFLT::~ConvertFromFLT()
{
}
osg::Group* ConvertFromFLT::convert(HeaderRecord* rec)
{
if (rec==NULL) return NULL;
return visitHeader(rec);
}
////////////////////////////////////////////////////////////////////
Record* ConvertFromFLT::getVertexFromPool(int nOffset)
{
VertexPaletteOffsetMap::iterator fitr = _VertexPaletteOffsetMap.find(nOffset);
if (fitr != _VertexPaletteOffsetMap.end())
{
return (*fitr).second;
}
else return NULL;
}
void ConvertFromFLT::regisiterVertex(int nOffset, Record* pRec)
{
_VertexPaletteOffsetMap[nOffset] = pRec;
}
////////////////////////////////////////////////////////////////////
osg::Group* ConvertFromFLT::visitInstanceDefinition(osg::Group& osgParent,InstanceDefinitionRecord* rec)
{
osg::Group* group = new osg::Group;
InstancePool* pInstancePool = rec->getFltFile()->getInstancePool();
visitAncillary(osgParent, *group, rec);
pInstancePool->addInstance((int)rec->getData()->iInstDefNumber,group);
visitPrimaryNode(*group, (PrimNodeRecord*)rec);
return group;
}
osg::Group* ConvertFromFLT::visitInstanceReference(osg::Group& osgParent,InstanceReferenceRecord* rec)
{
osg::Group* group;
InstancePool* pInstancePool = rec->getFltFile()->getInstancePool();
group = pInstancePool->getInstance((int)rec->getData()->iInstDefNumber);
if (group)
osgParent.addChild( group );
else
osg::notify(osg::INFO) << "Warning: cannot find the instance definition in flt file."<<std::endl;
return group;
}
osg::Group* ConvertFromFLT::visitAncillary(osg::Group& osgParent, osg::Group& osgPrimary, PrimNodeRecord* rec)
{
// Note: There are databases that contains nodes with both Matrix and GeneralMatrix
// ancillary records. We need just one of these to put into the scenegraph
// Nick.
bool mxFound = false;
osg::Group* parent = &osgParent;
// Visit ancillary records
for(int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
if (!child->isAncillaryRecord())
break;
switch (child->getOpcode())
{
case LONG_ID_OP:
visitLongID(osgPrimary, (LongIDRecord*)child);
break;
case GENERAL_MATRIX_OP:
// Note: Ancillary record creates osg node
if (!mxFound)
{
parent = visitGeneralMatrix(*parent, osgPrimary, (GeneralMatrixRecord*)child);
mxFound = true;
}
break;
case MATRIX_OP:
// Note: Ancillary record creates osg node
if (!mxFound)
{
parent = visitMatrix(*parent, osgPrimary, (MatrixRecord*)child);
mxFound = true;
}
break;
case COMMENT_OP:
visitComment(osgPrimary, (CommentRecord*)child);
break;
case COLOR_PALETTE_OP:
visitColorPalette(osgPrimary, (ColorPaletteRecord*)child);
break;
case LIGHT_SOURCE_PALETTE_OP:
visitLightSourcePalette(osgPrimary, (LightSourcePaletteRecord*)child);
break;
case MATERIAL_PALETTE_OP:
visitMaterialPalette(osgPrimary, (MaterialPaletteRecord*)child);
break;
case OLD_MATERIAL_PALETTE_OP:
visitOldMaterialPalette(osgPrimary, (OldMaterialPaletteRecord*)child);
break;
case TEXTURE_PALETTE_OP:
visitTexturePalette(osgPrimary, (TexturePaletteRecord*)child);
break;
case LIGHT_PT_APPEARANCE_PALETTE_OP:
visitLtPtAppearancePalette(osgPrimary, (LtPtAppearancePaletteRecord*)child);
break;
case LIGHT_PT_ANIMATION_PALETTE_OP:
visitLtPtAnimationPalette(osgPrimary, (LtPtAnimationPaletteRecord*)child);
break;
case VERTEX_PALETTE_OP:
visitVertexPalette(osgPrimary, (VertexPaletteRecord*)child);
break;
case VERTEX_C_OP:
visitVertex(osgPrimary, (VertexRecord*)child);
break;
case VERTEX_CN_OP:
visitNormalVertex(osgPrimary, (NormalVertexRecord*)child);
break;
case VERTEX_CNT_OP:
visitNormalTextureVertex(osgPrimary, (NormalTextureVertexRecord*)child);
break;
case VERTEX_CT_OP:
visitTextureVertex(osgPrimary, (TextureVertexRecord*)child);
break;
default:
#ifdef _DEBUG
osg::notify( osg::INFO ) << "flt::ConvertFromFLT::visitAncillary: "
<< "Unknown opcode: " << child->getOpcode() << "\n";
#endif
break;
}
}
return parent;
}
osg::Group* ConvertFromFLT::visitPrimaryNode(osg::Group& osgParent, PrimNodeRecord* rec)
{
osg::Group* osgPrim = NULL;
GeoSetBuilder geoSetBuilder;
GeoSetBuilder billboardBuilder;
// Visit
for(int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
if (child && child->isPrimaryNode())
{
DPRINT(stderr, "**************************************\nvisitPrimaryNode: Got child opcode %d\n", child->getOpcode()) ;
switch (child->getOpcode())
{
case MESH_OP:
if( ((MeshRecord*)child)->getData()->swTemplateTrans == 2) //Axis type rotate
visitMesh(osgParent, &billboardBuilder, (MeshRecord*)child);
else
visitMesh(osgParent, &geoSetBuilder, (MeshRecord*)child);
break;
case FACE_OP:
{
FaceRecord* fr = (FaceRecord*)child;
if( fr->getData()->swTemplateTrans == 2) //Axis type rotate
visitFace(&billboardBuilder, osgParent, fr);
else
visitFace(&geoSetBuilder, osgParent, fr);
}
break;
case LIGHT_POINT_OP:
visitLightPoint(osgParent, (LightPointRecord*)child);
break;
case INDEXED_LIGHT_PT_OP:
visitLightPointIndex(osgParent, (LightPointIndexRecord*)child);
break;
case LIGHT_PT_SYSTEM_OP:
osgPrim = visitLightPointSystem(osgParent, (LightPointSystemRecord*)child);
break;
case GROUP_OP:
osgPrim = visitGroup(osgParent, (GroupRecord*)child);
break;
case LIGHT_SOURCE_OP:
osgPrim = visitLightSource(osgParent, (LightSourceRecord*)child);
break;
case LOD_OP:
osgPrim = visitLOD(osgParent, (LodRecord*)child);
break;
case OLD_LOD_OP:
osgPrim = visitOldLOD(osgParent, (OldLodRecord*)child);
break;
case DOF_OP:
osgPrim = visitDOF(osgParent, (DofRecord*)child);
break;
case BSP_OP:
osgPrim = visitBSP(osgParent, (BSPRecord*)child);
break;
case SWITCH_OP:
osgPrim = visitSwitch(osgParent, (SwitchRecord*)child);
break;
case OBJECT_OP:
osgPrim = visitObject(osgParent, (ObjectRecord*)child);
break;
case INSTANCE_REFERENCE_OP:
osgPrim = visitInstanceReference(osgParent, (InstanceReferenceRecord*)child);
break;
case INSTANCE_DEFINITION_OP:
osgPrim = visitInstanceDefinition(osgParent, (InstanceDefinitionRecord*)child);
break;
case EXTERNAL_REFERENCE_OP:
osgPrim = visitExternal(osgParent, (ExternalRecord*)child);
break;
case ROAD_CONSTRUCTION_OP:
// treat road construction record as a group record for now
osgPrim = visitRoadConstruction(osgParent, (GroupRecord*)child);
break;
default:
#ifdef _DEBUG
osg::notify(osg::INFO) << "In ConvertFromFLT::visitPrimaryNode(), unknown opcode: " << child->getOpcode() << std::endl;
#endif
break;
}
}
}
if( !geoSetBuilder.empty() )
{
osg::Geode* geode = new osg::Geode;
geoSetBuilder.createOsgGeoSets(geode );
if (geode->getNumDrawables() > 0)
osgParent.addChild( geode );
}
if( !billboardBuilder.empty() )
{
osg::Billboard* billboard = new osg::Billboard;
billboardBuilder.createOsgGeoSets(billboard );
if (billboard->getNumDrawables() > 0)
osgParent.addChild( billboard );
}
return osgPrim;
}
void ConvertFromFLT::visitLongID(osg::Group& osgParent, LongIDRecord* rec)
{
SLongID *pSLongID = (SLongID*)rec->getData();
unsigned int stringLength = mystrnlen(pSLongID->szIdent,rec->getBodyLength());
osgParent.setName(std::string(pSLongID->szIdent,stringLength));
}
void ConvertFromFLT::visitComment(osg::Node& osgParent, CommentRecord* rec)
{
SComment *pSComment = (SComment*)rec->getData();
//std::cout << "ConvertFromFLT::visitComment '"<<std::string(pSComment->szComment,pSComment->RecHeader.length()-4)<<"'"<<std::endl;
//std::cout << "ConvertFromFLT::visitComment cstyle string '"<<pSComment->szComment<<"'"<<std::endl;
unsigned int stringLength = mystrnlen(pSComment->szComment,rec->getBodyLength());
std::string commentfield(pSComment->szComment,stringLength);
unsigned int front_of_line = 0;
unsigned int end_of_line = 0;
while (end_of_line<commentfield.size())
{
if (commentfield[end_of_line]=='\r')
{
osgParent.addDescription( std::string( commentfield, front_of_line, end_of_line-front_of_line) );
if (end_of_line+1<commentfield.size() &&
commentfield[end_of_line+1]=='\n') ++end_of_line;
++end_of_line;
front_of_line = end_of_line;
}
else if (commentfield[end_of_line]=='\n')
{
osgParent.addDescription( std::string( commentfield, front_of_line, end_of_line-front_of_line) );
++end_of_line;
front_of_line = end_of_line;
}
else ++end_of_line;
}
if (front_of_line<end_of_line)
{
osgParent.addDescription( std::string( commentfield, front_of_line, end_of_line-front_of_line) );
}
}
osg::Group* ConvertFromFLT::visitHeader(HeaderRecord* rec)
{
SHeader *pSHeader = (SHeader*)rec->getData();
// Version
_diOpenFlightVersion = pSHeader->diFormatRevLev;
osg::notify(osg::INFO) << "Version " << _diOpenFlightVersion << std::endl;
// Unit scale
if ( _doUnitsConversion )
{
switch (rec->getFltFile()->getDesiredUnits())
{
case FltFile::ConvertToMeters:
switch (pSHeader->swVertexCoordUnit)
{
case HeaderRecord::METERS:
_unitScale = 1.0;
break;
case HeaderRecord::KILOMETERS:
_unitScale = 1000.0;
break;
case HeaderRecord::FEET:
_unitScale = 0.3048;
break;
case HeaderRecord::INCHES:
_unitScale = 0.02540;
break;
case HeaderRecord::NAUTICAL_MILES:
_unitScale = 1852.0;
break;
default:
_unitScale = 1.0;
}
break;
case FltFile::ConvertToKilometers:
switch (pSHeader->swVertexCoordUnit)
{
case HeaderRecord::METERS:
_unitScale = 0.001;
break;
case HeaderRecord::KILOMETERS:
_unitScale = 1.0;
break;
case HeaderRecord::FEET:
_unitScale = 0.0003048;
break;
case HeaderRecord::INCHES:
_unitScale = 0.0000254;
break;
case HeaderRecord::NAUTICAL_MILES:
_unitScale = 1.852;
break;
default:
_unitScale = 1.0;
}
break;
case FltFile::ConvertToFeet:
switch (pSHeader->swVertexCoordUnit)
{
case HeaderRecord::METERS:
_unitScale = 3.2808399;
break;
case HeaderRecord::KILOMETERS:
_unitScale = 3280.839895;
break;
case HeaderRecord::FEET:
_unitScale = 1.0;
break;
case HeaderRecord::INCHES:
_unitScale = 0.0833333;
break;
case HeaderRecord::NAUTICAL_MILES:
_unitScale = 6076.1154856 ;
break;
default:
_unitScale = 1.0;
}
break;
case FltFile::ConvertToInches:
switch (pSHeader->swVertexCoordUnit)
{
case HeaderRecord::METERS:
_unitScale = 39.3700787;
break;
case HeaderRecord::KILOMETERS:
_unitScale = 39370.0787402;
break;
case HeaderRecord::FEET:
_unitScale = 12.0;
break;
case HeaderRecord::INCHES:
_unitScale = 1.0;
break;
case HeaderRecord::NAUTICAL_MILES:
_unitScale = 72913.3858268;
break;
default:
_unitScale = 1.0;
}
break;
case FltFile::ConvertToNauticalMiles:
switch (pSHeader->swVertexCoordUnit)
{
case HeaderRecord::METERS:
_unitScale = 0.0005399568;
break;
case HeaderRecord::KILOMETERS:
_unitScale = 0.5399568;
break;
case HeaderRecord::FEET:
_unitScale = 0.0001646;
break;
case HeaderRecord::INCHES:
_unitScale = 0.0000137;
break;
case HeaderRecord::NAUTICAL_MILES:
_unitScale = 1.0;
break;
default:
_unitScale = 1.0;
}
break;
default:
_unitScale = 1.0;
break;
}
}
else
{
_unitScale = 1.0;
}
// Flight v.11 & v.12 use integer coordinates
if (rec->getFlightVersion() < 13)
{
if (pSHeader->iMultDivUnit >= 0)
_unitScale *= (double)pSHeader->iMultDivUnit;
else
_unitScale /= (double)(-pSHeader->iMultDivUnit);
}
_bHdrRgbMode = (pSHeader->dwFlags & 0x40000000) ? true : false; // RGB space (=packed color)
// Create root group node
osg::Group* group = new osg::Group;
group->setName(pSHeader->szIdent);
visitAncillary(*group, *group, rec);
visitPrimaryNode(*group, rec);
return group;
}
/*osgParent*/
void ConvertFromFLT::visitColorPalette(osg::Group& , ColorPaletteRecord* rec)
{
if (!rec->getFltFile()->useInternalColorPalette()) return;
ColorPool* pColorPool = rec->getFltFile()->getColorPool();
int flightVersion = rec->getFlightVersion();
if (flightVersion > 13)
{
SColorPalette* pCol = (SColorPalette*)rec->getData();
int colors = (flightVersion >= 1500) ? 1024 : 512;
for (int i=0; i < colors; i++)
{
osg::Vec4 color(pCol->Colors[i].get());
color[3] = 1.0f; // Force alpha to one
pColorPool->addColor(i, color);
}
}
else // version 11, 12 & 13
{
SOldColorPalette* pCol = (SOldColorPalette*)rec->getData();
unsigned int i;
for (i=0; i < sizeof(pCol->Colors)/sizeof(pCol->Colors[0]); i++)
{
osg::Vec4 color(pCol->Colors[i].get());
color[3] = 1.0f; // Force alpha to one
pColorPool->addColor(i, color);
}
for (i=0; i < sizeof(pCol->FixedColors)/sizeof(pCol->FixedColors[0]); i++)
{
osg::Vec4 color(pCol->FixedColors[i].get());
color[3] = 1.0f; // Force alpha to one
pColorPool->addColor(i+(4096>>7), color);
}
}
}
/*osgParent*/
void ConvertFromFLT::visitLightSourcePalette(osg::Group& , LightSourcePaletteRecord* rec)
{
SLightSourcePalette* pLight = (SLightSourcePalette*)rec->getData();
osg::Light* light = new osg::Light();
light->setAmbient( osg::Vec4(
pLight->sfAmbientRGBA[0], pLight->sfAmbientRGBA[1],
pLight->sfAmbientRGBA[2], pLight->sfAmbientRGBA[3] ) );
light->setDiffuse( osg::Vec4(
pLight->sfDiffuseRGBA[0], pLight->sfDiffuseRGBA[1],
pLight->sfDiffuseRGBA[2], pLight->sfDiffuseRGBA[3] ) );
light->setSpecular( osg::Vec4(
pLight->sfSpecularRGBA[0], pLight->sfSpecularRGBA[1],
pLight->sfSpecularRGBA[2], pLight->sfSpecularRGBA[3] ) );
light->setConstantAttenuation( pLight->sfConstantAttuenation );
light->setLinearAttenuation( pLight->sfLinearAttuenation );
light->setQuadraticAttenuation( pLight->sfQuadraticAttuenation );
//light->setSpotExponent( pLight->sfDropoff );
//light->setSpotCutoff( pLight->sfCutoff );
LightPool* pLightPool = rec->getFltFile()->getLightPool();
pLightPool->addLight( pLight->diIndex, light );
}
/*osgParent*/
void ConvertFromFLT::visitMaterialPalette(osg::Group&, MaterialPaletteRecord* rec)
{
if (!rec->getFltFile()->useInternalMaterialPalette()) return;
SMaterial* pSMaterial = (SMaterial*)rec->getData();
MaterialPool* pMaterialPool = rec->getFltFile()->getMaterialPool();
if (pSMaterial && pMaterialPool)
{
MaterialPool::PoolMaterial* pPoolMat = new MaterialPool::PoolMaterial;
pPoolMat->Ambient = pSMaterial->Ambient;
pPoolMat->Diffuse = pSMaterial->Diffuse;
pPoolMat->Specular = pSMaterial->Specular;
pPoolMat->Emissive = pSMaterial->Emissive;
pPoolMat->sfShininess = pSMaterial->sfShininess;
pPoolMat->sfAlpha = pSMaterial->sfAlpha;
pMaterialPool->addMaterial((int)pSMaterial->diIndex, pPoolMat);
}
}
/*osgParent*/
void ConvertFromFLT::visitOldMaterialPalette(osg::Group& , OldMaterialPaletteRecord* rec)
{
if (!rec->getFltFile()->useInternalMaterialPalette()) return;
SOldMaterial* pSMaterial = (SOldMaterial*)rec->getData();
MaterialPool* pMaterialPool = rec->getFltFile()->getMaterialPool();
if (pSMaterial && pMaterialPool )
{
for (int i=0; i < 64; i++)
{
MaterialPool::PoolMaterial* pPoolMat = new MaterialPool::PoolMaterial;
pPoolMat->Ambient = pSMaterial->mat[i].Ambient;
pPoolMat->Diffuse = pSMaterial->mat[i].Diffuse;
pPoolMat->Specular = pSMaterial->mat[i].Specular;
pPoolMat->Emissive = pSMaterial->mat[i].Emissive;
pPoolMat->sfShininess = pSMaterial->mat[i].sfShininess;
pPoolMat->sfAlpha = pSMaterial->mat[i].sfAlpha;
pMaterialPool->addMaterial(i, pPoolMat);
}
}
}
/*osgParent*/
void ConvertFromFLT::visitTexturePalette(osg::Group& , TexturePaletteRecord* rec)
{
int nIndex;
char* pFilename;
if (!rec->getFltFile()->useInternalTexturePalette()) return;
if (rec->getFlightVersion() > 13)
{
STexturePalette* pTexture = (STexturePalette*)rec->getData();
pFilename = pTexture->szFilename;
nIndex = pTexture->diIndex;
}
else // version 11, 12 & 13
{
SOldTexturePalette* pOldTexture = (SOldTexturePalette*)rec->getData();
pFilename = pOldTexture->szFilename;
nIndex = pOldTexture->diIndex;
}
TexturePool* pTexturePool = rec->getFltFile()->getTexturePool();
if (pTexturePool == NULL) return;
std::string textureName(pFilename);
pTexturePool->addTextureName(nIndex, textureName);
CERR<<"pTexturePool->addTextureName("<<nIndex<<", "<<textureName<<")"<<std::endl;
}
void ConvertFromFLT::visitLtPtAppearancePalette(osg::Group& /*osgParent*/, LtPtAppearancePaletteRecord* rec)
{
SLightPointAppearancePalette* ltPtApp = (SLightPointAppearancePalette*)rec->getData();
LtPtAppearancePool* pool = rec->getFltFile()->getLtPtAppearancePool();
assert( pool );
if (ltPtApp && pool)
{
LtPtAppearancePool::PoolLtPtAppearance* entry = new LtPtAppearancePool::PoolLtPtAppearance;
entry->_iBackColorIdx = ltPtApp->backColor;
entry->_bIntensity = ltPtApp->intensity;
entry->_sfMinPixelSize = ltPtApp->minPixelSize;
entry->_sfMaxPixelSize = ltPtApp->maxPixelSize;
entry->_sfActualSize = ltPtApp->actualSize;
entry->_iDirectionality = ltPtApp->directionality;
entry->_sfHLobeAngle = ltPtApp->horizLobeAngle;
entry->_sfVLobeAngle = ltPtApp->vertLobeAngle;
entry->_sfLobeRollAngle = ltPtApp->lobeRollAngle;
pool->add(ltPtApp->index, entry);
}
}
void ConvertFromFLT::visitLtPtAnimationPalette(osg::Group& /*osgParent*/, LtPtAnimationPaletteRecord* rec)
{
SLightPointAnimationPalette* ltPtAnim = (SLightPointAnimationPalette*)rec->getData();
LtPtAnimationPool* pool = rec->getFltFile()->getLtPtAnimationPool();
assert( pool );
if (ltPtAnim && pool)
{
osg::ref_ptr<LtPtAnimationPool::PoolLtPtAnimation> entry = new LtPtAnimationPool::PoolLtPtAnimation;
entry->_name = std::string( ltPtAnim->name );
// Support sequenced animations
if ( (ltPtAnim->animType == LtPtAnimationPaletteRecord::SEQ_TYPE) &&
(ltPtAnim->numSequences > 0) )
{
osg::ref_ptr<osgSim::BlinkSequence> b = new osgSim::BlinkSequence;
for (int idx=0; idx<ltPtAnim->numSequences; idx++)
{
SLightPointAnimationSequence* seq = rec->sequence( idx );
osg::Vec4 color( 0.f, 0.f, 0.f, 0.f );
if (seq->seqState != LtPtAnimationPaletteRecord::SEQ_OFF)
{
// Sequence state is On or Color Change, so set the color to non-black
ColorPool* pColorPool = rec->getFltFile()->getColorPool();
color = pColorPool->getColor( seq->seqColor );
}
b->addPulse( seq->duration, color );
}
entry->_blink = b;
}
// Support strobe animations
else if (ltPtAnim->animType == LtPtAnimationPaletteRecord::STROBE_TYPE)
{
osg::ref_ptr<osgSim::BlinkSequence> b = new osgSim::BlinkSequence;
const float duration = .5f / ltPtAnim->period;
b->addPulse( duration, osg::Vec4( 0.f, 0.f, 0.f, 0.f ) );
b->addPulse( duration, osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );
entry->_blink = b;
}
pool->add( ltPtAnim->index, entry.get() );
}
}
/*osgParent*/
void ConvertFromFLT::visitVertexPalette(osg::Group& , VertexPaletteRecord* rec)
{
_diCurrentOffset = rec->getSize();
}
/*osgParent*/
void ConvertFromFLT::visitVertex(osg::Group& , VertexRecord* rec)
{
regisiterVertex(_diCurrentOffset, rec);
_diCurrentOffset += rec->getSize();
}
/*osgParent*/
void ConvertFromFLT::visitNormalVertex(osg::Group& , NormalVertexRecord* rec)
{
regisiterVertex(_diCurrentOffset, rec);
_diCurrentOffset += rec->getSize();
}
/*osgParent*/
void ConvertFromFLT::visitTextureVertex(osg::Group& , TextureVertexRecord* rec)
{
regisiterVertex(_diCurrentOffset, rec);
_diCurrentOffset += rec->getSize();
}
/*osgParent*/
void ConvertFromFLT::visitNormalTextureVertex(osg::Group& , NormalTextureVertexRecord* rec)
{
regisiterVertex(_diCurrentOffset, rec);
_diCurrentOffset += rec->getSize();
}
osg::Group* ConvertFromFLT::visitBSP(osg::Group& osgParent, BSPRecord* rec)
{
// create group node for the time being
osg::Group* group = new osg::Group;
group->setName(rec->getData()->szIdent);
visitAncillary(osgParent, *group, rec)->addChild( group );
visitPrimaryNode(*group, rec);
return group;
}
osg::Group* ConvertFromFLT::visitGroup(osg::Group& osgParent, GroupRecord* rec)
{
const int fltVer = rec->getFltFile()->getFlightVersion();
SGroup* currentGroup = (SGroup*) rec->getData();
const bool forwardAnim = (currentGroup->dwFlags & GroupRecord::FORWARD_ANIM)!=0;
// OpenFlight 15.8 adds backwards animations
const bool backwardAnim = ( (fltVer >= 1580) &&
((currentGroup->dwFlags & GroupRecord::BACKWARD_ANIM) != 0) );
// Regardless of forwards or backwards, animation could have swing bit set
const osg::Sequence::LoopMode loopMode = ( (currentGroup->dwFlags & GroupRecord::SWING_ANIM) == 0 ) ?
osg::Sequence::LOOP : osg::Sequence::SWING;
if( forwardAnim || backwardAnim)
{
osg::Sequence* animSeq = new osg::Sequence;
visitAncillary(osgParent, *animSeq, rec)->addChild( animSeq );
visitPrimaryNode(*animSeq, rec);
const int numReps = (fltVer >= 1580) ?
currentGroup->iLoopCount : 1000000;
const float frameDuration = (fltVer >= 1580) ?
currentGroup->fLoopDuration / (float)animSeq->getNumChildren() : 0.f;
animSeq->setDuration( frameDuration, numReps );
if ( forwardAnim )
animSeq->setInterval( loopMode, 0, -1 );
else // Backwards animation
animSeq->setInterval( loopMode, -1, 0 );
animSeq->setMode( osg::Sequence::START );
// Only set the name from the normal record ID if the visitAncillary()
// call didn't find a Long ID record on this group
if (animSeq->getName().length() == 0)
animSeq->setName(rec->getData()->szIdent);
return animSeq;
}
else
{
osg::Group* group = new osg::Group;
group->setName(rec->getData()->szIdent);
visitAncillary(osgParent, *group, rec)->addChild( group );
visitPrimaryNode(*group, rec);
return group;
}
}
osg::Group* ConvertFromFLT::visitLightSource(osg::Group& osgParent, LightSourceRecord* rec)
{
static int lightnum = 0;
LightPool* pLightPool = rec->getFltFile()->getLightPool();
SLightSource* pLSource = (SLightSource*) rec->getData();
/*
if ( !(pLSource->dwFlags & 1) ) { // enabled
return NULL;
}
*/
osg::LightSource* lightSource = new osg::LightSource();
osg::Light* pLight = pLightPool->getLight( pLSource->diIndex );
osg::Light* light = new osg::Light( *pLight );
light->setPosition( osg::Vec4(
pLSource->Coord.x(), pLSource->Coord.y(),
pLSource->Coord.z(), 1 ) );
light->setLightNum( lightnum );
lightSource->setLight( light );
lightSource->setLocalStateSetModes( osg::StateAttribute::ON );
osg::Node* node = &osgParent;
if ( 1 ) { //pLSource->dwFlags & 2 ) { // global
while ( !node->getParents().empty() ) {
node = *(node->getParents().begin());
}
}
lightSource->setStateSetModes( *(node->getOrCreateStateSet()),
osg::StateAttribute::ON );
lightnum++;
osgParent.addChild( lightSource );
visitPrimaryNode(*lightSource, rec);
return lightSource;
}
osg::Group* ConvertFromFLT::visitRoadConstruction(osg::Group& osgParent, GroupRecord* rec)
{
osg::Group* group = new osg::Group;
group->setName(rec->getData()->szIdent);
//cout<<"Converted a road construction node of ID "<<group->getName()<<" to group node."<<endl;
visitAncillary(osgParent, *group, rec)->addChild( group );
visitPrimaryNode(*group, rec);
return group;
}
osg::Group* ConvertFromFLT::visitLOD(osg::Group& osgParent, LodRecord* rec)
{
SLevelOfDetail* pSLOD = rec->getData();
osg::LOD* lod = new osg::LOD;
float64x3* pCenter = &pSLOD->Center;
lod->setCenter(osg::Vec3(pCenter->x(), pCenter->y(), pCenter->z())*_unitScale);
lod->setRange(0, pSLOD->dfSwitchOutDist*_unitScale,
pSLOD->dfSwitchInDist*_unitScale);
lod->setName(pSLOD->szIdent);
visitAncillary(osgParent, *lod, rec)->addChild( lod );
osg::Group* group = new osg::Group;
lod->addChild(group);
visitPrimaryNode(*group, rec);
return lod;
}
osg::Group* ConvertFromFLT::visitOldLOD(osg::Group& osgParent, OldLodRecord* rec)
{
SOldLOD* pSLOD = (SOldLOD*)rec->getData();
osg::LOD* lod = new osg::LOD;
lod->setCenter(osg::Vec3(
(float)pSLOD->Center[0],
(float)pSLOD->Center[1],
(float)pSLOD->Center[2])*_unitScale);
lod->setRange(0, ((float)pSLOD->dwSwitchOutDist)*_unitScale,
((float)pSLOD->dwSwitchInDist)*_unitScale);
lod->setName(pSLOD->szIdent);
visitAncillary(osgParent, *lod, rec)->addChild( lod );
osg::Group* group = new osg::Group;
lod->addChild(group);
visitPrimaryNode(*group, rec);
return lod;
}
// TODO: DOF node implemented as Group.
// Converted DOF to use transform - jtracy@ist.ucf.edu
osg::Group* ConvertFromFLT::visitDOF(osg::Group& osgParent, DofRecord* rec)
{
#define USE_DOFTransform
#if defined(USE_DOFTransform)
osgSim::DOFTransform* transform = new osgSim::DOFTransform;
transform->setName(rec->getData()->szIdent);
transform->setDataVariance(osg::Object::DYNAMIC);
visitAncillary(osgParent, *transform, rec)->addChild( transform );
visitPrimaryNode(*transform, (PrimNodeRecord*)rec);
SDegreeOfFreedom* p_data = rec->getData();
//now fill up members:
//tranlsations:
transform->setMinTranslate(osg::Vec3(_unitScale*p_data->dfX._dfMin,
_unitScale*p_data->dfY._dfMin,
_unitScale*p_data->dfZ._dfMin));
transform->setMaxTranslate(osg::Vec3(_unitScale*p_data->dfX._dfMax,
_unitScale*p_data->dfY._dfMax,
_unitScale*p_data->dfZ._dfMax));
transform->setCurrentTranslate(osg::Vec3(_unitScale*p_data->dfX._dfCurrent,
_unitScale*p_data->dfY._dfCurrent,
_unitScale*p_data->dfZ._dfCurrent));
transform->setIncrementTranslate(osg::Vec3(_unitScale*p_data->dfX._dfIncrement,
_unitScale*p_data->dfY._dfIncrement,
_unitScale*p_data->dfZ._dfIncrement));
//rotations:
transform->setMinHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfMin),
osg::inDegrees(p_data->dfPitch._dfMin),
osg::inDegrees(p_data->dfRoll._dfMin)));
transform->setMaxHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfMax),
osg::inDegrees(p_data->dfPitch._dfMax),
osg::inDegrees(p_data->dfRoll._dfMax)));
transform->setCurrentHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfCurrent),
osg::inDegrees(p_data->dfPitch._dfCurrent),
osg::inDegrees(p_data->dfRoll._dfCurrent)));
transform->setIncrementHPR(osg::Vec3(osg::inDegrees(p_data->dfYaw._dfIncrement),
osg::inDegrees(p_data->dfPitch._dfIncrement),
osg::inDegrees(p_data->dfRoll._dfIncrement)));
//scales:
transform->setMinScale(osg::Vec3(p_data->dfXscale._dfMin,
p_data->dfYscale._dfMin,
p_data->dfZscale._dfMin));
transform->setMaxScale(osg::Vec3(p_data->dfXscale._dfMax,
p_data->dfYscale._dfMax,
p_data->dfZscale._dfMax));
transform->setCurrentScale(osg::Vec3(p_data->dfXscale._dfCurrent,
p_data->dfYscale._dfCurrent,
p_data->dfZscale._dfCurrent));
transform->setIncrementScale(osg::Vec3(p_data->dfXscale._dfIncrement,
p_data->dfYscale._dfIncrement,
p_data->dfZscale._dfIncrement));
// compute the put matrix.
osg::Vec3 O ( p_data->OriginLocalDOF.x(),
p_data->OriginLocalDOF.y(),
p_data->OriginLocalDOF.z());
osg::Vec3 xAxis ( p_data->PointOnXaxis.x(),
p_data->PointOnXaxis.y(),
p_data->PointOnXaxis.z());
xAxis = xAxis - O;
xAxis.normalize();
osg::Vec3 xyPlane ( p_data->PointInXYplane.x(),
p_data->PointInXYplane.y(),
p_data->PointInXYplane.z());
xyPlane = xyPlane - O;
xyPlane.normalize();
osg::Vec3 normalz = xAxis ^ xyPlane;
normalz.normalize();
// get X, Y, Z axis of the DOF in terms of global coordinates
osg::Vec3 Rz = normalz;
if (Rz == osg::Vec3(0,0,0)) Rz[2] = 1;
osg::Vec3 Rx = xAxis;
if (Rx == osg::Vec3(0,0,0)) Rx[0] = 1;
osg::Vec3 Ry = Rz ^ Rx;
O *= _unitScale;
// create the putmatrix
osg::Matrix inv_putmat( Rx.x(), Rx.y(), Rx.z(), 0,
Ry.x(), Ry.y(), Ry.z(), 0,
Rz.x(), Rz.y(), Rz.z(), 0,
O.x(), O.y(), O.z(), 1);
transform->setInversePutMatrix(inv_putmat);
transform->setPutMatrix(osg::Matrix::inverse(inv_putmat));
/*
//and now do a little ENDIAN to put flags in ordewr as described in OpenFlight spec
unsigned long flags = p_data->dwFlags;
ENDIAN(flags);
//and setup limitation flags:
// transform->setLimitationFlags(flags);
*/
transform->setLimitationFlags(p_data->dwFlags);
return transform;
#else
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setName(rec->getData()->szIdent);
transform->setDataVariance(osg::Object::DYNAMIC);
visitAncillary(osgParent, *transform, rec)->addChild( transform );
visitPrimaryNode(*transform, (PrimNodeRecord*)rec);
SDegreeOfFreedom* p_data = rec->getData();
// get transformation to O_world
osg::Vec3 O ( p_data->OriginLocalDOF.x(),
p_data->OriginLocalDOF.y(),
p_data->OriginLocalDOF.z());
osg::Vec3 xAxis ( p_data->PointOnXaxis.x(),
p_data->PointOnXaxis.y(),
p_data->PointOnXaxis.z());
xAxis = xAxis - O;
xAxis.normalize();
osg::Vec3 xyPlane ( p_data->PointInXYplane.x(),
p_data->PointInXYplane.y(),
p_data->PointInXYplane.z());
xyPlane = xyPlane - O;
xyPlane.normalize();
osg::Vec3 normalz = xAxis ^ xyPlane;
normalz.normalize();
// get X, Y, Z axis of the DOF in terms of global coordinates
osg::Vec3 Rz = normalz;
if (Rz == osg::Vec3(0,0,0)) Rz[2] = 1;
osg::Vec3 Rx = xAxis;
if (Rx == osg::Vec3(0,0,0)) Rx[0] = 1;
osg::Vec3 Ry = Rz ^ Rx;
// create the putmatrix
osg::Matrix putmat( Rx.x(), Rx.y(), Rx.z(), 0,
Ry.x(), Ry.y(), Ry.z(), 0,
Rz.x(), Rz.y(), Rz.z(), 0,
O.x(), O.y(), O.z(), 1);
// apply DOF transformation
osg::Vec3 trans(_unitScale*p_data->dfX._dfCurrent,
_unitScale*p_data->dfY._dfCurrent,
_unitScale*p_data->dfZ._dfCurrent);
float roll_rad = osg::inDegrees(p_data->dfRoll._dfCurrent);
float pitch_rad = osg::inDegrees(p_data->dfPitch._dfCurrent);
float yaw_rad = osg::inDegrees(p_data->dfYaw._dfCurrent);
float sx = rec->getData()->dfXscale.current();
float sy = rec->getData()->dfYscale.current();
float sz = rec->getData()->dfZscale.current();
// this is the local DOF transformation
osg::Matrix dof_matrix = osg::Matrix::scale(sx, sy, sz)*
osg::Matrix::rotate(yaw_rad, 0.0f,0.0f,1.0f)*
osg::Matrix::rotate(roll_rad, 0.0f,1.0f,0.0f)*
osg::Matrix::rotate(pitch_rad, 1.0f,0.0f,0.0f)*
osg::Matrix::translate(trans);
// transforming local into global
dof_matrix.preMult(osg::Matrix::inverse(putmat));
cout << "putmat "<< putmat<<endl;
// transforming global into local
dof_matrix.postMult(putmat);
transform->setMatrix(dof_matrix);
return transform;
#endif
}
osg::Group* ConvertFromFLT::visitSwitch(osg::Group& osgParent, SwitchRecord* rec)
{
SSwitch *pSSwitch = (SSwitch*)rec->getData();
osgSim::MultiSwitch* osgSwitch = new osgSim::MultiSwitch;
osgSwitch->setName(pSSwitch->szIdent);
visitAncillary(osgParent, *osgSwitch, rec)->addChild( osgSwitch );
visitPrimaryNode(*osgSwitch, (PrimNodeRecord*)rec);
unsigned int totalNumChildren = (unsigned int)rec->getNumChildren();
if (totalNumChildren!=osgSwitch->getNumChildren())
{
// only convert the children we agree on,
// however, there could be a chance that ordering of children might
// be different if there a children that hanvn't mapped across...
if (totalNumChildren>osgSwitch->getNumChildren()) totalNumChildren=osgSwitch->getNumChildren();
osg::notify(osg::INFO)<<"Warning::OpenFlight loader has come across an incorrectly handled switch."<<std::endl;
osg::notify(osg::INFO)<<" The number of OpenFlight children ("<<rec->getNumChildren()<<") "<<std::endl;
osg::notify(osg::INFO)<<" exceeds the number converted to OSG ("<<osgSwitch->getNumChildren()<<")"<<std::endl;
}
// for each mask in the FLT Switch node
for (int itMask=0; itMask<pSSwitch->nMasks; ++itMask)
{
// I don't think we need to create a group node for each mask any more
// create a osg group node
//osg::ref_ptr<osg::Group> group = new osg::Group;
//osgSwitch->addChild( group.get() );
// for each child in the FLT Switch node
for (unsigned int itChild=0; itChild<totalNumChildren; ++itChild)
{
// test if this child is active in the current mask (itMask)
unsigned int nMaskBit = itChild % 32;
unsigned int nMaskWord = itMask * pSSwitch->nWordsInMask + itChild / 32;
osgSwitch->setValue(itMask, itChild, (pSSwitch->aMask[nMaskWord] & (uint32(1) << nMaskBit))!=0 );
}
// now the group contain all the childrens that are active in the current mask (itMask)
}
osgSwitch->setActiveSwitchSet(pSSwitch->nCurrentMask);
return osgSwitch;
}
osg::Group* ConvertFromFLT::visitObject(osg::Group& osgParent, ObjectRecord* rec)
{
SObject *pSObject = (SObject*)rec->getData();
osg::Group* object = new osg::Group;
object->setName(pSObject->szIdent);
visitAncillary(osgParent, *object, rec)->addChild( object );
unsigned short wPrevTransparency = _wObjTransparency;
_wObjTransparency = pSObject->wTransparency;
visitPrimaryNode(*object, (PrimNodeRecord*)rec);
_wObjTransparency = wPrevTransparency;
if ( pSObject->dwFlags & 0xFC000000) // some of the 6 defined flag bits are set
{
std::string desc("flt object flags: 0x");
char cflags[33];
sprintf( cflags, "%X", (unsigned int)pSObject->dwFlags );
desc = desc + cflags;
object->getDescriptions().push_back( desc );
}
return object;
}
void ConvertFromFLT::setCullFaceAndWireframe ( const SFace *pSFace, osg::StateSet *osgStateSet, DynGeoSet *dgset )
{
//
// Cull face & wireframe
//
switch(pSFace->swDrawFlag)
{
case FaceRecord::SOLID_BACKFACED:
// Enable backface culling
{
osg::CullFace* cullface = new osg::CullFace;
cullface->setMode(osg::CullFace::BACK);
osgStateSet->setAttributeAndModes(cullface, osg::StateAttribute::ON);
}
break;
case FaceRecord::SOLID_NO_BACKFACE:
// Disable backface culling
osgStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
break;
case FaceRecord::WIREFRAME_NOT_CLOSED:
dgset->setPrimType(osg::PrimitiveSet::LINE_STRIP);
break;
case FaceRecord::WIREFRAME_CLOSED:
dgset->setPrimType(osg::PrimitiveSet::LINE_LOOP);
break;
case FaceRecord::OMNIDIRECTIONAL_LIGHT:
case FaceRecord::UNIDIRECTIONAL_LIGHT:
case FaceRecord::BIDIRECTIONAL_LIGHT:
dgset->setPrimType(osg::PrimitiveSet::POINTS);
break;
}
}
void ConvertFromFLT::setDirectionalLight()
{
/*
TODO:
int directionalLight = pSFace->swDrawFlag & (BIT3 | BIT4);
switch(directionalLight)
{
case FaceRecord::OMNIDIRECTIONAL_LIGHT:
break;
case FaceRecord::UNIDIRECTIONAL_LIGHT:
break;
case FaceRecord::BIDIRECTIONAL_LIGHT:
break;
}
*/
}
void ConvertFromFLT::setLightingAndColorBinding ( const FaceRecord *rec, const SFace *pSFace, osg::StateSet *osgStateSet, DynGeoSet *dgset )
{
//
// Lighting and color binding
//
if (rec->getFlightVersion() > 13)
{
switch(pSFace->swLightMode)
{
case FaceRecord::FACE_COLOR:
// Use face color, not illuminated
osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
dgset->setColorBinding( /*osg::Geometry::BIND_OVERALL*/ osg::Geometry::BIND_PER_PRIMITIVE );
break;
case FaceRecord::VERTEX_COLOR:
// Use vertex colors, not illuminated
osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
dgset->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
break;
case FaceRecord::FACE_COLOR_LIGHTING:
// Use face color and vertex normal
osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::ON );
dgset->setColorBinding( /*osg::Geometry::BIND_OVERALL*/ osg::Geometry::BIND_PER_PRIMITIVE);
dgset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
break;
case FaceRecord::VERTEX_COLOR_LIGHTING:
// Use vertex color and vertex normal
osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::ON );
dgset->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
dgset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
break;
default :
osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
dgset->setColorBinding( osg::Geometry::BIND_OVERALL );
break;
}
}
else // Version 11, 12 & 13
{
osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
dgset->setColorBinding( osg::Geometry::BIND_OVERALL /*BIND_PERPRIM*/ );
}
}
void ConvertFromFLT::setColor ( FaceRecord *rec, SFace *pSFace, DynGeoSet *dgset, bool &bBlend )
{
//
// Face Color
//
if (pSFace->swTexWhite && (pSFace->iTexturePattern != -1))
{
// Render textured polygons white
_faceColor.set(1, 1, 1, 1);
}
else
{
ColorPool* pColorPool = rec->getFltFile()->getColorPool();
_faceColor.set(1, 1, 1, 1);
if (rec->getFlightVersion() > 13)
{
if (!(pSFace->dwFlags & FaceRecord::NO_COLOR_BIT))
{
bool bPackedColor =
_bHdrRgbMode ||
(pSFace->dwFlags & FaceRecord::PACKED_COLOR_BIT) ||
(pColorPool == NULL);
if (bPackedColor)
_faceColor = pSFace->PrimaryPackedColor.get();
else
{
if (rec->getFlightVersion() >= 1540)
{
_faceColor =
pColorPool->getColor(pSFace->dwPrimaryColorIndex);
}
else // Version 14.2, 15.0
{
// The field now called wPrimaryNameIndex was
// originally the primary color/intensity code
// for OpenFlight v14.2 and v15.0 files
_faceColor =
pColorPool->getColor(pSFace->wPrimaryNameIndex);
}
}
}
}
else // Version 11, 12 & 13
{
bool bPackedColor = _bHdrRgbMode || (pColorPool == NULL);
if (bPackedColor)
_faceColor = pSFace->PrimaryPackedColor.get();
else
_faceColor = pColorPool->getOldColor(pSFace->wPrimaryNameIndex);
}
}
// Face color alpha
_faceColor[3] = 1.0f - ((float)pSFace->wTransparency / 65535.0f);
if (pSFace->wTransparency > 0) bBlend = true;
if ((dgset->getColorBinding() == osg::Geometry::BIND_OVERALL)
|| (dgset->getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE))
dgset->addColor(_faceColor);
}
void ConvertFromFLT::setMaterial ( FaceRecord *rec, SFace *pSFace, osg::StateSet *osgStateSet, bool &bBlend )
{
//
// Material
//
MaterialPool* pMaterialPool = rec->getFltFile()->getMaterialPool();
if (pMaterialPool)
{
MaterialPool::PoolMaterial* pSMaterial = pMaterialPool->getMaterial((int)pSFace->iMaterial);
if (pSMaterial)
{
osg::Material* osgMaterial = new osg::Material;
osg::Vec4 ambient;
osg::Vec4 diffuse;
osg::Vec4 specular;
osg::Vec4 emissiv;
float alpha;
// In contrast to the OpenFlight Specification this works!
alpha = pSMaterial->sfAlpha *
(1.0f - ((float)pSFace->wTransparency / 65535.0f)) *
(1.0f - ((float)_wObjTransparency / 65535.0f));
ambient[0] = pSMaterial->Ambient[0] * _faceColor[0];
ambient[1] = pSMaterial->Ambient[1] * _faceColor[1];
ambient[2] = pSMaterial->Ambient[2] * _faceColor[2];
ambient[3] = alpha;
diffuse[0] = pSMaterial->Diffuse[0] * _faceColor[0];
diffuse[1] = pSMaterial->Diffuse[1] * _faceColor[1];
diffuse[2] = pSMaterial->Diffuse[2] * _faceColor[2];
diffuse[3] = alpha;
specular[0] = pSMaterial->Specular[0];
specular[1] = pSMaterial->Specular[1];
specular[2] = pSMaterial->Specular[2];
specular[3] = alpha;
emissiv[0] = pSMaterial->Emissive[0];
emissiv[1] = pSMaterial->Emissive[1];
emissiv[2] = pSMaterial->Emissive[2];
emissiv[3] = alpha;
osgMaterial->setColorMode(osg::Material::OFF);
osgMaterial->setAmbient(osg::Material::FRONT_AND_BACK, ambient);
osgMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
osgMaterial->setSpecular(osg::Material::FRONT_AND_BACK, specular);
osgMaterial->setEmission(osg::Material::FRONT_AND_BACK, emissiv);
osgMaterial->setAlpha(osg::Material::FRONT_AND_BACK, alpha);
osgMaterial->setShininess(osg::Material::FRONT_AND_BACK, pSMaterial->sfShininess);
osgStateSet->setAttribute(osgMaterial);
if (alpha < 1.0f) bBlend = true;
}
}
}
void ConvertFromFLT::setTexture ( FaceRecord *rec, SFace *pSFace, osg::StateSet *osgStateSet, DynGeoSet *dgset, bool &bBlend )
{
//
// Texture
//
if (pSFace->iTexturePattern != -1)
{
TexturePool* pTexturePool = rec->getFltFile()->getTexturePool();
if (pTexturePool)
{
int nIndex = (int)pSFace->iTexturePattern;
flt::AttrData *textureAttrData = pTexturePool->getTexture(nIndex,rec->getFltFile()->getOptions());
osg::StateSet *textureStateSet;
if (textureAttrData)
textureStateSet = textureAttrData->stateset;
else
textureStateSet = NULL;
if (textureStateSet)
{
//We got detail texture, so we got detailTexture stateset and add a TexEnvCombine attribute
// To add simple detail texture we just use texture unit 1 to store detail
//As Creators help says, if Mag. Filter General is set to Modulate Detail we just
//add the detail, but if it set to Add Detail then we got a lighter image, so we
//use scale_rgb and scale_alpha of osg::TexEnvCombine to make this effect
// Julian Ortiz, June 18th 2003.
flt::AttrData *detailTextureAttrData = NULL;
if (pSFace->iDetailTexturePattern != -1) {
int nIndex2 = (int)pSFace->iDetailTexturePattern;
detailTextureAttrData = pTexturePool->getTexture(nIndex2,rec->getFltFile()->getOptions());
if (detailTextureAttrData && detailTextureAttrData->stateset) {
osg::Texture2D *detTexture = dynamic_cast<osg::Texture2D*>(detailTextureAttrData->stateset->getTextureAttribute( 0, osg::StateAttribute::TEXTURE));
textureStateSet->setTextureAttributeAndModes(1,detTexture,osg::StateAttribute::ON);
osg::TexEnvCombine *tec1 = new osg::TexEnvCombine;
float scale = (detailTextureAttrData->modulateDetail==0)?2.0f:4.0f;
tec1->setScale_RGB(scale);
tec1->setScale_Alpha(scale);
textureStateSet->setTextureAttribute( 1, tec1,osg::StateAttribute::ON );
}
}
// If a detail texture structure exists, set the texture
// coordinate scalars on the current DynGeoSet, so the correct
// detail texture coordinates get generated later.
if (pSFace->iDetailTexturePattern != -1 &&
detailTextureAttrData &&
detailTextureAttrData->stateset)
{
// Set the texture coordinate scalars
dgset->setDetailTexCoords(detailTextureAttrData->txDetail_m,
detailTextureAttrData->txDetail_n);
// Make sure detail texturing is on
dgset->enableDetailTexture();
}
else
{
// Make sure detail texturing is off
dgset->disableDetailTexture();
}
// Merge face stateset with texture stateset
osgStateSet->merge(*textureStateSet);
// Alpha channel in texture?
osg::Texture2D *osgTexture = dynamic_cast<osg::Texture2D*>(textureStateSet->getTextureAttribute( 0, osg::StateAttribute::TEXTURE));
if (osgTexture)
{
osg::Image* osgImage = osgTexture->getImage();
if (getUseTextureAlphaForTransparancyBinning() && osgImage->isImageTranslucent()) bBlend = true;
}
#if 0 // Started to experiment with OpenFlight texture mapping modes
if (pSFace->iTextureMapIndex > -1)
{
osg::TexGen* osgTexGen = new osg::TexGen;
osgTexGen->setMode(osg::TexGen::SPHERE_MAP);
osgStateSet->setTextueAttributeAndModes( 0, osgTexGen,osg::StateAttribute::ON);
}
#endif
dgset->setTextureBinding(osg::Geometry::BIND_PER_VERTEX);
}
}
}
}
void ConvertFromFLT::setTransparency ( osg::StateSet *osgStateSet, bool &bBlend )
{
//
// Transparency
//
if (bBlend)
{
osg::BlendFunc* osgBlendFunc = new osg::BlendFunc();
osgBlendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
osgStateSet->setAttribute(osgBlendFunc);
osgStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
osgStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}
}
void
ConvertFromFLT::addMultiTexture( DynGeoSet* dgset, MultiTextureRecord* mtr )
{
osg::Geometry* geom = dgset->getGeometry();
if (geom==0 || mtr==0 || !mtr->isAncillaryRecord())
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) has been passed invalid paramters."<<std::endl;
return;
}
SMultiTexture* mt = reinterpret_cast<SMultiTexture*>(mtr->getData());
if (mt==0)
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) mtr->getData() not valid SMultiTexture*."<<std::endl;
return;
}
CERR << "ConvertFromFLT::addMultiTexture\n";
int l = 0;
for ( int i = 0; i < 8; i++ )
{
if ( (1 << (32-i)) & mt->layers )
{
CERR << "Has layer " << i << "\n";
mt->data[l].endian();
CERR << "texture: " << mt->data[l].texture << "\n";
CERR << "effect: " << mt->data[l].effect << "\n";
CERR << "mapping: " << mt->data[l].mapping << "\n";
CERR << "data: " << mt->data[l].data << "\n";
TexturePool* pTexturePool = mtr->getFltFile()->getTexturePool();
assert( pTexturePool );
if (!pTexturePool)
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) pTexturePool invalid."<<std::endl;
return;
}
// Get the texture attribute data from the texture pool
flt::AttrData *textureAttrData = dynamic_cast<flt::AttrData *> (pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFltFile()->getOptions()));
CERR << "pTexturePool->getTexture((int)mt->data[l].texture): " << pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFltFile()->getOptions()) << "\n";
if (!textureAttrData)
{
CERR << "unable to set up multi-texture layer." << std::endl;
return;
}
// Get the texture state set from the attribute data structure
osg::StateSet *textureStateSet = textureAttrData->stateset;
CERR << "textureStateSet: " << textureStateSet << "\n";
if (!textureStateSet)
{
CERR << "unable to set up multi-texture layer." << std::endl;
return;
}
osg::Texture2D *texture = dynamic_cast<osg::Texture2D*>(textureStateSet->getTextureAttribute(0, osg::StateAttribute::TEXTURE));
CERR << "texture: " << texture << "\n";
osg::StateSet* texture_stateset = new osg::StateSet;
CERR << "texture_stateset: " << texture_stateset << "\n";
if (!texture)
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) texture invalid."<<std::endl;
return;
}
texture_stateset->setTextureAttributeAndModes(i, texture,osg::StateAttribute::ON);
osg::StateAttribute* texenv_0 = textureStateSet->getTextureAttribute( 0, osg::StateAttribute::TEXENV );
if (texenv_0)
{
texture_stateset->setTextureAttribute( i, texenv_0);
}
else
{
osg::TexEnv* osgTexEnv = new osg::TexEnv;
osgTexEnv->setMode(osg::TexEnv::MODULATE);
texture_stateset->setTextureAttribute( i, osgTexEnv );
}
CERR << "geom: " << geom << "\n";
CERR << ", referenceCount: "
<< geom->referenceCount() << "\n";
// Get the state set from the current geometry
osg::StateSet* geom_stateset = geom->getStateSet();
CERR << "geom_stateset: " << geom_stateset << "\n";
// See if we need to merge or set the texture state set on the
// geometry
if ( geom_stateset )
{
geom_stateset->merge( *texture_stateset );
CERR << "Merging layer " << i << "\n";
} else {
geom->setStateSet( texture_stateset );
CERR << "Setting layer " << i << "\n";
}
// Set the texture binding on the current texture unit to
// per-vertex
dgset->setTextureBinding(i, osg::Geometry::BIND_PER_VERTEX);
l++;
}
}
}
void
ConvertFromFLT::addUVList( DynGeoSet* dgset, UVListRecord* uvr )
{
if (!dgset || !uvr || !uvr->isAncillaryRecord())
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addUVList( DynGeoSet*, UVListRecord*) has been passed invalid paramters."<<std::endl;
return;
}
SUVList* uvl = reinterpret_cast<SUVList*>(uvr->getData());
if (!uvl)
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addUVList( DynGeoSet*, UVListRecord*) uvr->getData() is invalid."<<std::endl;
return;
}
CERR << "ConvertFromFLT::addUVList\n";
int l = 0;
int num_coords = dgset->coordListSize();
for ( int i = 0; i < 8; i++ )
{
if ( (1 << (32-i)) & uvl->layers )
{
CERR << "Has layer " << i << "\n";
// Assume we are working with vertex lists for now
for ( int v = l*num_coords; v < (l+1)*num_coords; v++ )
{
uvl->coords.vertex[v].endian();
CERR << "( u: " << uvl->coords.vertex[v].coords[1] << ", "
<< "v: " << uvl->coords.vertex[v].coords[0] << ")\n";
/// FIXME: should be (x,y) instead of (y,x) - ENDIAN problem???
// Add the texture coordinates to the current DynGeoSet
dgset->addTCoord(i,
osg::Vec2(uvl->coords.vertex[v].coords[1],
uvl->coords.vertex[v].coords[0]));
}
l++;
}
}
}
void ConvertFromFLT::visitFace(GeoSetBuilder* pBuilder, osg::Group& osgParent, FaceRecord* rec)
{
DynGeoSet* dgset = pBuilder->getDynGeoSet();
osg::StateSet* osgStateSet = dgset->getStateSet();
SFace *pSFace = (SFace*)rec->getData();
bool bBlend = false;
if (rec->getFlightVersion() > 13)
{
if (pSFace->dwFlags & FaceRecord::HIDDEN_BIT)
return;
}
// Various properties.
setCullFaceAndWireframe ( pSFace, osgStateSet, dgset );
setDirectionalLight();
setLightingAndColorBinding ( rec, pSFace, osgStateSet, dgset );
setColor ( rec, pSFace, dgset, bBlend );
setMaterial ( rec, pSFace, osgStateSet, bBlend );
// Subface
if (rec->getParent()->isOfType(FACE_OP))
{
if (_nSubfaceLevel > 0)
{
osg::PolygonOffset* polyoffset = new osg::PolygonOffset;
if (polyoffset)
{
polyoffset->setFactor(-1.0f*_nSubfaceLevel);
polyoffset->setUnits(-20.0f*_nSubfaceLevel);
osgStateSet->setAttributeAndModes(polyoffset,osg::StateAttribute::ON);
}
}
}
// Texture.
setTexture ( rec, pSFace, osgStateSet, dgset, bBlend );
// Transparency
setTransparency ( osgStateSet, bBlend );
// Vertices
addVertices(pBuilder, osgParent, rec);
// Visit ancillary records
for(int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
if (!child->isAncillaryRecord())
break;
switch (child->getOpcode())
{
case MULTI_TEXTURE_OP:
{
MultiTextureRecord* mtr =
dynamic_cast<MultiTextureRecord*>(child);
if (!mtr)
{
osg::notify( osg::WARN ) << "flt::ConvertFromFLT::visitFace(GeoSetBuilder*, FaceRecord*) found invalid MultiTextureRecord*"<<std::endl;
return;
}
// original code, but causes crash becayse addPrimitive can invalidate teh dgset pointer.
addMultiTexture( dgset, mtr );
// addMultiTexture( pBuilder->getDynGeoSet(), mtr );
}
break;
default:
#ifdef _DEBUG
osg::notify( osg::NOTICE) << "flt::ConvertFromFLT::visitFace: "
<< "Unhandled opcode: " << child->getOpcode() << "\n";
#endif
break;
}
}
// Add face to builder pool
pBuilder->addPrimitive();
// Look for subfaces
{
_nSubfaceLevel++;
int n;
for(n=0; n<rec->getNumChildren(); n++)
{
Record* child = rec->getChild(n);
if (child && child->isOfType(FACE_OP))
visitFace(pBuilder, osgParent, (FaceRecord*)child);
}
_nSubfaceLevel--;
}
}
/* C.Holtz: These global variables are to support the REPLICATE ancillary record
used for lightpoint strings in 15.7 (it really should support replication of any
node, but I really only needed lightpoint strings and it's such a hack, I don't
want to propagate it anywhere is doesn't really need to be :) */
static osg::Matrix theMatrix ;
static osg::Matrix theGeneralMatrix ;
static osg::Vec3 from, delta ;
static int num_replicate ;
static int got_gm, got_m, got_t, got_replicate ;
// Return number of vertices added to builder.
int ConvertFromFLT::addVertices(GeoSetBuilder* pBuilder, osg::Group& osgParent, PrimNodeRecord* primRec)
{
int i;
int vertices=0;
DynGeoSet* dgset = pBuilder->getDynGeoSet();
/* Clear the replicate stuff each time through */
got_gm = got_m = got_t = got_replicate = 0 ;
DPRINT(stderr, ">>> addVerticies...%d children\n", primRec->getNumChildren()) ;
for(i=0; i < primRec->getNumChildren(); i++)
{
Record* child = primRec->getChild(i);
if (child == NULL) break;
DPRINT(stderr, " child opcode = %d\n", child->getOpcode()) ;
switch (child->getOpcode())
{
case VERTEX_LIST_OP:
vertices += visitVertexList(pBuilder, (VertexListRecord*)child);
break;
case LOCAL_VERTEX_POOL_OP:
vertices += visitLocalVertexPool(pBuilder, (LocalVertexPoolRecord *)child);
break;
case TRANSLATE_OP:
if (1) {
// This will be for replicated verticies
STranslate *pSTranslate = ((TranslateRecord *)child)->getData() ;
// scale position.
from.set(pSTranslate->From[0],pSTranslate->From[1],pSTranslate->From[2]) ;
from *= _unitScale ;
delta.set(pSTranslate->Delta[0],pSTranslate->Delta[1],pSTranslate->Delta[2]) ;
delta *= _unitScale ;
DPRINT(stderr, " ** addVerticies: Got Translate: F=%lf, %lf, %lf / D=%lf, %lf, %lf\n",
from[0], from[1], from[2], delta[0], delta[1], delta[2]) ;
got_t = 1 ;
}
break ;
case MATRIX_OP:
{
// This will be for replicated verticies
SMatrix *pSMatrix = ((MatrixRecord *)child)->getData() ;
for(int i=0;i<4;++i)
{
for(int j=0;j<4;++j)
{
theMatrix(i,j) = pSMatrix->sfMat[i][j];
}
}
// scale position.
osg::Vec3 pos = theMatrix.getTrans();
theMatrix *= osg::Matrix::translate(-pos);
pos *= (float)_unitScale;
theMatrix *= osg::Matrix::translate(pos);
if(dprint)std::cout << " ** addVerticies: Got Matrix: " << theMatrix << std::endl ;
got_m = 1 ;
}
break ;
case GENERAL_MATRIX_OP:
{
// This will be for replicated verticies
SGeneralMatrix *pSMatrix = ((GeneralMatrixRecord *)child)->getData() ;
for(int i=0;i<4;++i)
{
for(int j=0;j<4;++j)
{
theGeneralMatrix(i,j) = pSMatrix->sfMat[i][j];
}
}
// scale position.
osg::Vec3 pos = theGeneralMatrix.getTrans();
theGeneralMatrix *= osg::Matrix::translate(-pos);
pos *= (float)_unitScale;
theGeneralMatrix *= osg::Matrix::translate(pos);
if(dprint)std::cout << " ** addVerticies: Got GeneralMatrix: " << theGeneralMatrix << std::endl ;
got_gm = 1 ;
}
break ;
case REPLICATE_OP:
{
// This will be for replicated verticies
SReplicate *pSReplicate = (SReplicate *)(child->getData()) ;
ENDIAN(pSReplicate->iNumber) ;
num_replicate = pSReplicate->iNumber ;
DPRINT(stderr, " ** addVerticies: Got Replicate: %d times\n", num_replicate) ;
got_replicate = 1 ;
}
break ;
case LIGHT_POINT_OP:
{
/* Apparently, lightpoints are allowed to be clildren
of faces in older versions (<15.4?) */
DPRINT(stderr, " ** addVerticies: Got LIGHT_POINT_OP\n") ;
visitLightPoint(osgParent, (LightPointRecord*)child) ;
}
break ;
default :
vertices += addVertex(pBuilder, child);
break;
}
}
if (vertices > 0)
{
if (dgset->getPrimType() == osg::PrimitiveSet::POINTS)
{
for (i=0; i < vertices; i++)
dgset->addPrimLen(1);
}
else
{
dgset->addPrimLen(vertices);
}
}
return vertices;
}
int ConvertFromFLT::visitVertexList(GeoSetBuilder* pBuilder, VertexListRecord* rec)
{
DynGeoSet* dgset = pBuilder->getDynGeoSet();
int vertices = rec->numberOfVertices();
DPRINT(stderr, ">>> visitVertexList...%d vertices\n", vertices) ;
// Add vertices to GeoSetBuilder
for (int j=0; j < vertices; j++)
{
Record* vertex = getVertexFromPool(rec->getVertexPoolOffset(j));
if (vertex)
addVertex(pBuilder, vertex);
}
// Visit ancillary records
for(int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
CERR << "OPCODE: " << child->getOpcode() << "\n";
if (!child->isAncillaryRecord())
break;
switch (child->getOpcode())
{
case UV_LIST_OP:
{
UVListRecord* uvr =
dynamic_cast<UVListRecord*>(child);
assert( uvr );
addUVList( dgset, uvr );
}
break;
case MULTI_TEXTURE_OP:
{
CERR2 << "MULTI_TEXTURE_OP in visitVertexList\n";
MultiTextureRecord* mtr =
dynamic_cast<MultiTextureRecord*>(child);
assert( mtr );
addMultiTexture( dgset, mtr );
}
break;
default:
#ifdef _DEBUG
osg::notify( osg::NOTICE )
<< "flt::ConvertFromFLT::visitVertexList: "
<< "Unhandled opcode: " << child->getOpcode() << "\n";
#endif
break;
}
}
return vertices;
}
// Return 1 if record is a known vertex record else return 0.
int ConvertFromFLT::addVertex(DynGeoSet* dgset, Record* rec)
{
int i ;
DPRINT(stderr, ">>> addVertex...") ;
switch(rec->getOpcode())
{
case VERTEX_C_OP:
DPRINT(stderr, "VERTEX_C_OP\n") ;
{
SVertex* pVert = (SVertex*)rec->getData();
osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z());
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_VERTEX_COLOR(dgset, pVert, rec->getFltFile()->getColorPool())
}
break;
case VERTEX_CN_OP:
DPRINT(stderr, "VERTEX_CN_OP\n") ;
{
SNormalVertex* pVert = (SNormalVertex*)rec->getData();
osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z());
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if (dgset->getNormalBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_NORMAL(dgset, pVert)
if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_VERTEX_COLOR(dgset, pVert, rec->getFltFile()->getColorPool())
}
break;
case VERTEX_CNT_OP:
DPRINT(stderr, "VERTEX_CNT_OP\n") ;
{
SNormalTextureVertex* pVert = (SNormalTextureVertex*)rec->getData();
osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z());
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if (dgset->getNormalBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_NORMAL(dgset, pVert)
if (dgset->getTextureBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_TCOORD(dgset, pVert)
if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_VERTEX_COLOR(dgset, pVert, rec->getFltFile()->getColorPool())
}
break;
case VERTEX_CT_OP:
DPRINT(stderr, "VERTEX_CT_OP\n") ;
{
STextureVertex* pVert = (STextureVertex*)rec->getData();
osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z());
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if (dgset->getTextureBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_TCOORD(dgset, pVert)
if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_VERTEX_COLOR(dgset, pVert, rec->getFltFile()->getColorPool())
}
break;
case OLD_VERTEX_OP:
DPRINT(stderr, "OLD_VERTEX_OP\n") ;
{
SOldVertex* pVert = (SOldVertex*)rec->getData();
osg::Vec3 coord(pVert->v[0], pVert->v[1], pVert->v[2]);
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if ((dgset->getTextureBinding() == osg::Geometry::BIND_PER_VERTEX)
&& (rec->getSize() >= sizeof(SOldVertex)))
ADD_OLD_TCOORD(dgset, pVert)
}
break;
case OLD_VERTEX_COLOR_OP:
DPRINT(stderr, "OLD_VERTEX_COLOR_OP\n") ;
{
SOldVertexColor* pVert = (SOldVertexColor*)rec->getData();
osg::Vec3 coord(pVert->v[0], pVert->v[1], pVert->v[2]);
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_OLD_COLOR(dgset, pVert, rec->getFltFile()->getColorPool())
if ((dgset->getTextureBinding() == osg::Geometry::BIND_PER_VERTEX)
&& (rec->getSize() >= sizeof(SOldVertexColor)))
ADD_OLD_TCOORD(dgset, pVert)
}
break;
case OLD_VERTEX_COLOR_NORMAL_OP:
DPRINT(stderr, "OLD_VERTEX_COLOR_NORMAL_OP\n") ;
{
SOldVertexColorNormal* pVert = (SOldVertexColorNormal*)rec->getData();
osg::Vec3 coord(pVert->v[0], pVert->v[1], pVert->v[2]);
coord *= (float)_unitScale;
dgset->addCoord(coord);
if ( got_replicate ) {
/* Handle vertex replication */
DPRINT(stderr, " ### addVertex: Replicating (%f,%f,%f) %d times...\n",
coord[0], coord[1], coord[2], num_replicate) ;
for ( i = 0 ; i < num_replicate ; i++ ) {
if ( got_t ) {
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
} else {
/* If we didn't get a translate record, try to get the delta from the matrix */
delta = theMatrix.getTrans() ;
coord += delta ;
DPRINT(stderr, " >> Replicated vertex as (%f,%f,%f)\n",
coord[0], coord[1], coord[2]) ;
dgset->addCoord(coord) ;
}
}
}
if (dgset->getNormalBinding() == osg::Geometry::BIND_PER_VERTEX)
{
osg::Vec3 normal(pVert->n[0], pVert->n[1], pVert->n[2]);
normal /= (float)(1L<<30);
dgset->addNormal(normal);
}
if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX)
ADD_OLD_COLOR(dgset, pVert, rec->getFltFile()->getColorPool())
if ((dgset->getTextureBinding() == osg::Geometry::BIND_PER_VERTEX)
&& (rec->getSize() >= sizeof(SOldVertexColorNormal)))
ADD_OLD_TCOORD(dgset, pVert)
}
break;
default :
DPRINT(stderr, "*** UNKNOWN (%d)***\n", rec->getOpcode()) ;
return 0;
}
/* Clear out the replicate stuff so that it doesn't get reused if we
return to this function from somewhere other than addVerticies() */
got_gm = got_m = got_t = got_replicate = 0 ;
return 1;
}
// general matrix
osg::Group* ConvertFromFLT::visitGeneralMatrix(osg::Group& osgParent, const osg::Group& /*osgPrimary*/, GeneralMatrixRecord* rec)
{
SGeneralMatrix* pSMatrix = (SGeneralMatrix*)rec->getData();
osg::MatrixTransform* transform = new osg::MatrixTransform;
osg::Matrix m;
for(int i=0;i<4;++i)
{
for(int j=0;j<4;++j)
{
m(i,j) = pSMatrix->sfMat[i][j];
}
}
// scale position.
osg::Vec3 pos = m.getTrans();
m *= osg::Matrix::translate(-pos);
pos *= (float)_unitScale;
m *= osg::Matrix::translate(pos);
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(m);
osgParent.addChild(transform);
return transform;
}
// matrix record
osg::Group* ConvertFromFLT::visitMatrix(osg::Group& osgParent, const osg::Group& /*osgPrimary*/, MatrixRecord* rec)
{
SMatrix* pSMatrix = (SMatrix*)rec->getData();
osg::MatrixTransform* transform = new osg::MatrixTransform;
osg::Matrix m;
for(int i=0;i<4;++i)
{
for(int j=0;j<4;++j)
{
m(i,j) = pSMatrix->sfMat[i][j];
}
}
// scale position.
osg::Vec3 pos = m.getTrans();
m *= osg::Matrix::translate(-pos);
pos *= (float)_unitScale;
m *= osg::Matrix::translate(pos);
transform->setDataVariance(osg::Object::STATIC);
transform->setMatrix(m);
osgParent.addChild(transform);
return transform;
}
osg::Group* ConvertFromFLT::visitExternal(osg::Group& osgParent, ExternalRecord* rec)
{
FltFile* pFile = rec->getExternal();
osg::Group* external = NULL;
if (pFile)
{
pFile->setDesiredUnits( rec->getFltFile()->getDesiredUnits() );
external = pFile->convert();
if (external)
{
osg::Group *tempParent = visitAncillary(osgParent, *external, rec);
// In the situation in which only one model is required from an
// externally referenced file, it would be more efficient to only
// convert that one model from the FltFile records. (This would be
// the preferred method if this loader is rewritten.) However,
// since this situation is fairly rare and it is currently much
// more straight forward to work with the OSG structure, we will
// just pull out the part of the OSG tree that is needed at this
// point.
// If a model name was specified, find and add the node with
// that name. Otherwise, add the entire tree.
std::string modelName = rec->getModelName();
if ( modelName.empty() )
{
// Add the entire externally referenced file
tempParent->addChild(external);
}
else
{
// Find the specified model
FindExternalModelVisitor findExternalModelVisitor;
findExternalModelVisitor.setModelName( modelName );
external->accept( findExternalModelVisitor );
osg::Node *model = findExternalModelVisitor.getModel();
if (model)
{
tempParent->addChild(model);
}
else
{
osg::notify(osg::WARN) << "In ConvertFromFLT::visitExternal,"
<< " the requested model " << modelName
<< " was not found in external file "
<< rec->getFilename() << std::endl;
}
}
}
}
return external;
}
void ConvertFromFLT::visitLightPoint(GeoSetBuilder* pBuilder,osg::Group& osgParent, LightPointRecord* rec)
{
DynGeoSet* dgset = pBuilder->getDynGeoSet();
osg::StateSet* stateSet = dgset->getStateSet();
SLightPoint *pSLightPoint = (SLightPoint*)rec->getData();
dgset->setPrimType(osg::PrimitiveSet::POINTS);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateSet->setMode(GL_POINT_SMOOTH, osg::StateAttribute::ON);
dgset->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
osg::Point* point = new osg::Point;
if (point)
{
/*
point->setSize(pSLightPoint->sfSize);
stateSet->setAttributeAndModes( point, osg::StateAttribute::ON );
// point->setFadeThresholdSize(const float fadeThresholdSize);
// point->setDistanceAttenuation(const Vec3& distanceAttenuation);
// point->setStateSetModes(*stateSet, osg::StateAttribute::ON); // GL_POINT_SMOOTH
*/
//change to:
point->setSize(pSLightPoint->afActualPixelSize);
point->setFadeThresholdSize(pSLightPoint->sfTranspFalloff);
//numbers that are going to appear are "experimental"
point->setDistanceAttenuation(osg::Vec3(0.0001, 0.0005, 0.00000025));
point->setMinSize(pSLightPoint->sfMinPixelSize);
point->setMaxSize(pSLightPoint->sfMaxPixelSize);
stateSet->setAttributeAndModes( point, osg::StateAttribute::ON );
stateSet->setMode(GL_POINT_SMOOTH, osg::StateAttribute::ON);
stateSet->setAttributeAndModes(new osg::BlendFunc, osg::StateAttribute::ON);
}
// Visit vertices
addVertices(pBuilder, osgParent, rec);
pBuilder->addPrimitive();
}
void ConvertFromFLT::visitLightPoint(osg::Group& osgParent, LightPointRecord* rec)
{
SLightPoint *pSLightPoint = (SLightPoint*)rec->getData();
GeoSetBuilder pBuilder;
DynGeoSet* dgset = pBuilder.getDynGeoSet();
dgset->setPrimType(osg::PrimitiveSet::POINTS);
dgset->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
dgset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
osgSim::LightPointNode *lpNode = new osgSim::LightPointNode();
for(int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
if( child->classOpcode() == COMMENT_OP) visitComment(*lpNode, (CommentRecord*)child);
}
DPRINT(stderr, "visitLightPoint: visiting node '%s'...(%d children)\n", pSLightPoint->szIdent, rec->getNumChildren()) ;
lpNode->setName(pSLightPoint->szIdent) ;
lpNode->setMinPixelSize( pSLightPoint->sfMinPixelSize);
lpNode->setMaxPixelSize( pSLightPoint->sfMaxPixelSize);
DPRINT(stderr, " MinPixelSize = %f\n", pSLightPoint->sfMinPixelSize) ;
DPRINT(stderr, " MaxPixelSize = %f\n", pSLightPoint->sfMaxPixelSize) ;
addVertices(&pBuilder, osgParent, rec);
const DynGeoSet::CoordList& coords = dgset->getCoordList();
const DynGeoSet::ColorList& colors = dgset->getColorList();
const DynGeoSet::NormalList& norms = dgset->getNormalList();
DPRINT(stderr, " Num Coords=%d, Num Colors=%d, Num Norms=%d\n", coords.size(), colors.size(), norms.size()) ;
bool directional = false;
int numInternalLightPoints = 0; // Number of osgSim::LightPoint objects to add per OpenFlight light point vertex
switch (pSLightPoint->diDirection)
{
case 0: // Omnidirectional;
DPRINT(stderr, " OMNIDIRECTIONAL\n") ;
directional = false;
numInternalLightPoints = 1;
break;
case 1: // Unidirectional;
DPRINT(stderr, " UNIDIRECTIONAL\n") ;
directional = true;
numInternalLightPoints = 1;
break;
case 2: // Bidirectional;
DPRINT(stderr, " BIDIRECTIONAL\n") ;
directional = true;
numInternalLightPoints = 2;
break;
}
float lobeVert=0.f, lobeHorz=0.f, lobeRoll=0.f;
if ( directional)
{
lobeVert = osg::DegreesToRadians( pSLightPoint->sfLobeVert );
lobeHorz = osg::DegreesToRadians( pSLightPoint->sfLobeHoriz );
lobeRoll = osg::DegreesToRadians( pSLightPoint->sfLobeRoll );
}
float pointRadius = pSLightPoint->afActualPixelSize * _unitScale;
DPRINT(stderr, " Vertical Lobe Angle = %f\n", osg::RadiansToDegrees(lobeVert)) ;
DPRINT(stderr, " Horizontal Lobe Angle = %f\n", osg::RadiansToDegrees(lobeHorz)) ;
DPRINT(stderr, " Lobe Roll Angle = %f\n", osg::RadiansToDegrees(lobeRoll)) ;
DPRINT(stderr, " Point Radius = %f\n", pointRadius) ;
/* From my experience during all this testing, I think it's safe to assume that
each light point in a single light point node should share the same color
and normal. Even if multiple normals are found, they seem to be wrong for some
reason */
osg::Vec4 color( 1.0f, 1.0f, 1.0f, 1.0f);
osg::Vec3 normal( 1.0f, 0.0f, 0.0f);
for ( unsigned int nl = 0; nl < coords.size(); nl++)
{
//if( nl < colors.size()) color = colors[nl];
if( colors.size()>0) color = colors[0];
DPRINT(stderr, " Color = %f, %f, %f, %f\n", color.x(), color.y(), color.z(), color.w()) ;
osgSim::LightPoint lp( true, coords[ nl], color, pSLightPoint->sfIntensityFront, pointRadius);
if( pSLightPoint->diDirection )
{
DPRINT(stderr, " LP is directional...\n") ;
if ( !pSLightPoint->diDirectionalMode ) {
DPRINT(stderr, "%%%%%%%% WARNING: diDirection is set, but diDirectionalMode is off!!!\n") ;
}
// calc elevation angles
//if( nl < norms.size()) normal = norms[nl];
if( norms.size()>0) normal = norms[0];
DPRINT(stderr, " Normal = %f, %f, %f\n", normal.x(), normal.y(), normal.z()) ;
// Verify normal. If normal is 0,0,0, then LP isn't really directional
if ( (fabsf(normal.x()) < 0.0001) && (fabsf(normal.y()) < 0.0001) && (fabsf(normal.z()) < 0.0001) ) {
DPRINT(stderr, "%%%%%%%% WARNING: diDirection is set, but normal is not set!!!\n") ;
DPRINT(stderr, " ADDING LIGHTPOINT\n") ;
lpNode->addLightPoint( lp);
continue ;
}
if ( normal.isNaN() ) {
DPRINT(stderr, "%%%%%%%% WARNING: diDirection is set, but normal is NaN!!!\n") ;
DPRINT(stderr, " ADDING LIGHTPOINT\n") ;
lpNode->addLightPoint( lp);
continue ;
}
lp._sector = new osgSim::DirectionalSector( normal, lobeHorz, lobeVert, lobeRoll);
if( pSLightPoint->diDirection == 2 )
{
DPRINT(stderr, " ** LP is BIdirectional...\n") ;
osg::Vec4 backcolor = pSLightPoint->dwBackColor.get() ;
if ( backcolor.w() == 0.0 ) backcolor[3] = 1.0 ;
osgSim::LightPoint lp2( true, coords[ nl], backcolor, 1.0f, pointRadius);
DPRINT(stderr, " Backface Color = %f, %f, %f, %f\n", backcolor.x(), backcolor.y(), backcolor.z(), backcolor.w()) ;
// calc elevation angles
osg::Vec3 backnormal = - normal ;
DPRINT(stderr, " Normal = %f, %f, %f\n", backnormal.x(), backnormal.y(), backnormal.z()) ;
lp2._sector = new osgSim::DirectionalSector( backnormal, lobeHorz, lobeVert, lobeRoll);
DPRINT(stderr, " ADDING BACKFACING LIGHTPOINT\n") ;
lpNode->addLightPoint(lp2);
}
}
DPRINT(stderr, " ADDING LIGHTPOINT\n") ;
lpNode->addLightPoint( lp);
}
DPRINT (stderr, "lpNode has %d children\n", lpNode->getNumLightPoints()) ;
osgParent.addChild( lpNode);
}
// OpenFlight 15.8 (1580)
// Light point records contain indices into appearance and animation palettes.
// Need to look up the palette entries to determine how the light points
// look (and behave).
void ConvertFromFLT::visitLightPointIndex(osg::Group& osgParent, LightPointIndexRecord* rec)
{
SLightPointIndex *ltPtIdx = (SLightPointIndex*)rec->getData();
LtPtAppearancePool* appPool = rec->getFltFile()->getLtPtAppearancePool();
LtPtAppearancePool::PoolLtPtAppearance* ltPtApp = appPool->get( ltPtIdx->iAppearanceIndex );
if (!ltPtApp)
return; // Appearance index out of range
LtPtAnimationPool* animPool = rec->getFltFile()->getLtPtAnimationPool();
LtPtAnimationPool::PoolLtPtAnimation* ltPtAnim = NULL;
if (ltPtIdx->iAnimationIndex >= 0)
{
ltPtAnim = animPool->get( ltPtIdx->iAnimationIndex );
if (!ltPtAnim)
return; // Animation index out of range
}
GeoSetBuilder pBuilder;
DynGeoSet* dgset = pBuilder.getDynGeoSet();
dgset->setPrimType(osg::PrimitiveSet::POINTS);
dgset->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
dgset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
osgSim::LightPointNode *lpNode = new osgSim::LightPointNode();
for (int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
if( child->classOpcode() == COMMENT_OP) visitComment(*lpNode, (CommentRecord*)child);
}
lpNode->setMinPixelSize( ltPtApp->_sfMinPixelSize );
lpNode->setMaxPixelSize( ltPtApp->_sfMaxPixelSize );
addVertices(&pBuilder, osgParent, rec);
const DynGeoSet::CoordList& coords = dgset->getCoordList();
const DynGeoSet::ColorList& colors = dgset->getColorList();
const DynGeoSet::NormalList& norms = dgset->getNormalList();
bool directional = false;
int numInternalLightPoints = 0; // Number of osgSim::LightPoint objects to add per OpenFlight light point vertex
switch (ltPtApp->_iDirectionality)
{
case 0: // Omnidirectional;
directional = false;
numInternalLightPoints = 1;
break;
case 1: // Unidirectional;
directional = true;
numInternalLightPoints = 1;
break;
case 2: // Bidirectional;
directional = true;
numInternalLightPoints = 2;
break;
}
float lobeVert=0.f, lobeHorz=0.f, lobeRoll=0.f;
if ( directional)
{
lobeVert = osg::DegreesToRadians( ltPtApp->_sfVLobeAngle );
lobeHorz = osg::DegreesToRadians( ltPtApp->_sfHLobeAngle );
lobeRoll = osg::DegreesToRadians( ltPtApp->_sfLobeRollAngle );
}
float pointRadius = ltPtApp->_sfActualSize * _unitScale;
for (unsigned int nl = 0; nl < coords.size(); nl++)
{
// Could add 1 or 2 internal light points, 2 for bidirectional
for (int i=0; i<numInternalLightPoints; i++)
{
osg::Vec4 color( 1.0f, 1.0f, 1.0f, 1.0f);
if ( (i==0) && (nl < colors.size()) )
color = colors[nl];
else if (i==1)
{
// Get back color
ColorPool* pColorPool = rec->getFltFile()->getColorPool();
color = pColorPool->getColor( ltPtApp->_iBackColorIdx );
}
osgSim::BlinkSequence* blink = NULL;
if (ltPtAnim && ltPtAnim->_blink.valid())
blink = ltPtAnim->_blink.get();
// note in corbin's code the ltPtApp->_bIntensity was set to 1.0, however,
// I have left the original setting in place.
osgSim::LightPoint lp( true, coords[nl], color, ltPtApp->_bIntensity, pointRadius,
0, blink );
if (directional)
{
// calc elevation angles
osg::Vec3 normal( 1.0f, 0.0f, 0.0f);
if (nl < norms.size())
normal = norms[nl];
if (i==1)
// Negate the normal for the back facing internal light point
normal = -normal;
lp._sector = new osgSim::DirectionalSector( normal, lobeHorz, lobeVert, lobeRoll);
}
lpNode->addLightPoint(lp);
}
}
osgParent.addChild(lpNode);
}
// OpenFlight 15.8 (1580)
// Light point systems allow an application to control intensity, animation
// state, and on/off state of all child light point nodes from a single node.
// On/off state implemented with an osgSim::MultiSwitch. Set 0 turns all children
// off, set 1 turns them on. Applications can define other sets if desired, or
// redefine these sets.
// Children LightPointNodes all have a reference to a common LightPointState object
// An application controls intensity and animation state parameters by finding
// the first child of the Light Point System MultiSwitch, calling
// getLightPointState(), and setting intensity and animation state accordingly.
osg::Group* ConvertFromFLT::visitLightPointSystem(osg::Group& osgParent, LightPointSystemRecord* rec)
{
SLightPointSystem *ltPtSys = (SLightPointSystem*)rec->getData();
osgSim::MultiSwitch* system = new osgSim::MultiSwitch;
osg::ref_ptr<osgSim::LightPointSystem> lightState = new osgSim::LightPointSystem;
// Attach children
visitAncillary( osgParent, *system, rec )->addChild( system );
visitPrimaryNode( *system, rec );
system->setName( ltPtSys->ident );
// Set default sets: 0 for all off, 1 for all on
system->setAllChildrenOn( 1 );
system->setAllChildrenOff( 0 );
// Set initial on/off state
unsigned int initialSet = ( (ltPtSys->flags & 0x80000000) != 0 ) ? 1 : 0;
system->setActiveSwitchSet( initialSet );
lightState->setIntensity( ltPtSys->intensity );
switch( ltPtSys->animationState )
{
// Note that OpenFlight 15.8 spec says 0 means on and 1 means off.
// However, if animation is set on in Creator, it stores a 1, and
// a zero is stored for off! So, for now, we ignore the spec...
case 0:
lightState->setAnimationState( osgSim::LightPointSystem::ANIMATION_OFF );
break;
default:
case 1:
lightState->setAnimationState( osgSim::LightPointSystem::ANIMATION_ON );
break;
case 2:
lightState->setAnimationState( osgSim::LightPointSystem::ANIMATION_RANDOM );
break;
}
// Set light point state in all children
int errorChildren = 0;
for ( unsigned int i=0; i<system->getNumChildren(); i++)
{
osg::Node* child = system->getChild( i );
if (osgSim::LightPointNode* lpn = dynamic_cast<osgSim::LightPointNode*>(child))
lpn->setLightPointSystem (lightState.get() );
else
// Should never have a non-LightPointNode child
errorChildren++;
}
if (errorChildren > 0)
osg::notify( osg::WARN ) << "ConvertFromFLT::visitLightPointSystem found " << errorChildren << " non-LightPointNode child(ren)." << std::endl;
return ( (osg::Group*) system );
}
void ConvertFromFLT::visitMesh ( osg::Group &parent, GeoSetBuilder *pBuilder, MeshRecord *rec )
{
DynGeoSet* dgset = pBuilder->getDynGeoSet();
osg::StateSet *osgStateSet = dgset->getStateSet();
SFace *pSFace = (SFace *) rec->getData();
bool bBlend = false;
// See if it's hidden.
if ( rec->getFlightVersion() > 13 && flt::hasBits ( pSFace->dwFlags, (uint32) MeshRecord::HIDDEN_BIT ) )
return;
// Set the various properties.
setCullFaceAndWireframe ( pSFace, osgStateSet, dgset );
setDirectionalLight();
setLightingAndColorBinding ( rec, pSFace, osgStateSet, dgset );
setColor ( rec, pSFace, dgset, bBlend );
setMaterial ( rec, pSFace, osgStateSet, bBlend );
setTexture ( rec, pSFace, osgStateSet, dgset, bBlend );
setTransparency ( osgStateSet, bBlend );
// Add the vertices.
addVertices ( pBuilder, parent, rec );
// Add the mesh primitives.
addMeshPrimitives ( parent, pBuilder, rec );
// Visit ancillary records
for(int i=0; i < rec->getNumChildren(); i++)
{
Record* child = rec->getChild(i);
if (!child->isAncillaryRecord())
break;
switch (child->getOpcode())
{
case MULTI_TEXTURE_OP:
{
CERR2 << "MULTI_TEXTURE_OP in visitMesh\n";
MultiTextureRecord* mtr =
dynamic_cast<MultiTextureRecord*>(child);
assert( mtr );
addMultiTexture( dgset, mtr );
}
break;
default:
#ifdef _DEBUG
osg::notify( osg::NOTICE ) << "flt::ConvertFromFLT::visitMesh: "
<< "Unhandled opcode: " << child->getOpcode() << "\n";
#endif
break;
}
}
}
int ConvertFromFLT::addMeshPrimitives ( osg::Group &parent, GeoSetBuilder *pBuilder, MeshRecord *rec )
{
// The count of the mesh primitives added.
int count = 0;
// Loop through all the children.
for ( int i = 0; i < rec->getNumChildren(); ++i )
{
// Get the i'th child.
Record *child = rec->getChild ( i );
// If it is a mesh primitive...
if ( MESH_PRIMITIVE_OP == child->getOpcode() )
{
// Visit this mesh primitive.
visitMeshPrimitive ( parent, pBuilder, (MeshPrimitiveRecord *) child );
++count;
}
}
// Return the number of mesh primitives added.
return count;
}
int ConvertFromFLT::visitLocalVertexPool ( GeoSetBuilder *, LocalVertexPoolRecord *rec )
{
// Make the given instance the current one.
_currentLocalVertexPool = rec;
// We didn't add any vertices.
return 0;
}
void ConvertFromFLT::visitMeshPrimitive ( osg::Group &parent, GeoSetBuilder *pBuilder, MeshPrimitiveRecord *mesh )
{
if ( !mesh )
{
osg::notify(osg::NOTICE)<<"Warning:ConvertFromFLT::visitMeshPrimitive () mesh is 0, unable to process."<<std::endl;
return;
}
osg::Geode *geode = new osg::Geode();
osg::Geometry *geometry = new osg::Geometry();
LocalVertexPoolRecord *pool = _currentLocalVertexPool;
if (!pool)
{
osg::notify(osg::NOTICE)<<"Warning:ConvertFromFLT::visitMeshPrimitive () pool is 0, unable to process."<<std::endl;
return;
}
// Set the correct primitive type.
switch ( mesh->getData()->primitiveType )
{
case MeshPrimitiveRecord::TRIANGLE_STRIP:
geometry->addPrimitiveSet ( new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,0,mesh->getNumVertices()) );
break;
case MeshPrimitiveRecord::TRIANGLE_FAN:
geometry->addPrimitiveSet ( new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,0,mesh->getNumVertices()) );
break;
case MeshPrimitiveRecord::QUADRILATERAL_STRIP:
geometry->addPrimitiveSet ( new osg::DrawArrays(osg::PrimitiveSet::QUAD_STRIP,0,mesh->getNumVertices()) );
break;
case MeshPrimitiveRecord::INDEXED_POLYGON:
geometry->addPrimitiveSet ( new osg::DrawArrays(osg::PrimitiveSet::POLYGON,0,mesh->getNumVertices()) );
break;
default:
osg::notify(osg::NOTICE)<<"Warning:ConvertFromFLT::visitMeshPrimitive () unknown MeshPrimitiveRecord type."<<std::endl;
return;
}
// Add the vertex properties.
setMeshCoordinates ( mesh->getNumVertices(), pool, mesh, geometry );
setMeshNormals ( mesh->getNumVertices(), pool, mesh, geometry );
setMeshColors ( mesh->getNumVertices(), pool, mesh, geometry );
setMeshTexCoordinates ( mesh->getNumVertices(), pool, mesh, geometry );
DynGeoSet* dgset = pBuilder->getDynGeoSet();
osg::StateSet* osgStateSet = dgset->getStateSet();
geometry->setStateSet( osgStateSet );
// Add the geometry to the geode.
geode->addDrawable ( geometry );
// Add the geode to the parent.
parent.addChild ( geode );
}
uint32 ConvertFromFLT::setMeshCoordinates ( const uint32 &numVerts, const LocalVertexPoolRecord *pool, MeshPrimitiveRecord *mesh, osg::Geometry *geometry )
{
if (!pool || !mesh || !geometry)
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshCoordinates passed null objects."<<std::endl;
}
// If there aren't any coordinates...
if ( false == pool->hasAttribute ( LocalVertexPoolRecord::POSITION ) )
return 0;
// Allocate the vertices.
osg::Vec3Array *coords = new osg::Vec3Array(numVerts);
if ( NULL == coords )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshCoordinates out of memory."<<std::endl;
return 0;
}
// Declare outside of loop.
uint32 i ( 0 ), index ( 0 );
float64 px, py, pz;
// Loop through all the vertices.
for ( i = 0; i < numVerts; ++i )
{
// Get the i'th index into the vertex pool.
if ( !mesh->getVertexIndex ( i, index ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshCoordinates out of bounds."<<std::endl;
return 0;
}
// Get the coordinate (using "index").
if ( !pool->getPosition ( index, px, py, pz ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshCoordinates out of bounds."<<std::endl;
return 0;
}
// Add the coordinate.
(*coords)[i].set ( (float) px, (float) py, (float) pz );
}
// Set the mesh coordinates.
geometry->setVertexArray ( coords );
// Return the number of coordinates added.
return i;
}
uint32 ConvertFromFLT::setMeshNormals ( const uint32 &numVerts, const LocalVertexPoolRecord *pool, MeshPrimitiveRecord *mesh, osg::Geometry *geometry )
{
if (!pool || !mesh || !geometry)
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshNormals passed null objects."<<std::endl;
}
// If there aren't any coordinates...
if ( false == pool->hasAttribute ( LocalVertexPoolRecord::NORMAL ) )
return 0;
// Allocate the normals.
osg::Vec3Array *normals = new osg::Vec3Array(numVerts);
if ( NULL == normals )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshNormals out of memory."<<std::endl;
return 0;
}
// Declare outside of loop.
uint32 i ( 0 ), index ( 0 );
float32 x, y, z;
// Loop through all the vertices.
for ( i = 0; i < numVerts; ++i )
{
// Get the i'th index into the vertex pool.
if ( !mesh->getVertexIndex ( i, index ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshNormals out of bounds."<<std::endl;
return 0;
}
// Get the normal (using "index").
if ( !pool->getNormal ( index, x, y, z ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshNormals out of bounds."<<std::endl;
return 0;
}
// Add the normal.
(*normals)[i].set ( x, y, z );
}
// Set the mesh normals.
geometry->setNormalArray( normals );
geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
// Return the number of normals added.
return i;
}
uint32 ConvertFromFLT::setMeshColors ( const uint32 &numVerts, const LocalVertexPoolRecord *pool, MeshPrimitiveRecord *mesh, osg::Geometry *geometry )
{
if (!pool || !mesh || !geometry)
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshColors passed null objects."<<std::endl;
}
// If there aren't any colors...
if ( false == pool->hasAttribute ( LocalVertexPoolRecord::RGB_COLOR ) )
return 0;
// Allocate the normals.
osg::Vec4Array *colors = new osg::Vec4Array(numVerts);
if ( NULL == colors )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshColors out of memory."<<std::endl;
return 0;
}
// Declare outside of loop.
uint32 i ( 0 ), index ( 0 );
float32 red, green, blue, alpha;
// Loop through all the vertices.
for ( i = 0; i < numVerts; ++i )
{
// Get the i'th index into the vertex pool.
if ( false == mesh->getVertexIndex ( i, index ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshColors out of bounds."<<std::endl;
return 0;
}
// Get the color (using "index").
if ( false == pool->getColorRGBA ( index, red, green, blue, alpha ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshColors out of bounds."<<std::endl;
return 0;
}
// Add the coordinate.
(*colors)[i].set ( red, green, blue, alpha );
}
// Set the mesh coordinates.
geometry->setColorArray ( colors );
geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
// Return the number of colors added.
return i;
}
void ConvertFromFLT::setMeshTexCoordinates ( const uint32 &numVerts, const LocalVertexPoolRecord *pool, MeshPrimitiveRecord *mesh, osg::Geometry *geometry )
{
if (!pool || !mesh || !geometry)
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshTexCoordinates passed null objects."<<std::endl;
}
// Don't know the best way to do this in C++ without breaking
// data encapsulation rules or ending up with silly cut-and-paste
// code
//
std::vector<LocalVertexPoolRecord::AttributeMask> lAttrList( 8 );
lAttrList[0] = LocalVertexPoolRecord::BASE_UV;
lAttrList[1] = LocalVertexPoolRecord::UV_1;
lAttrList[2] = LocalVertexPoolRecord::UV_2;
lAttrList[3] = LocalVertexPoolRecord::UV_3;
lAttrList[4] = LocalVertexPoolRecord::UV_4;
lAttrList[5] = LocalVertexPoolRecord::UV_5;
lAttrList[6] = LocalVertexPoolRecord::UV_6;
lAttrList[7] = LocalVertexPoolRecord::UV_7;
osg::notify(osg::INFO) << "flt2osg::setMeshTexCoordinates() "
<< "Attribute masks in list."
<< std::endl;
// Check for texture coordinates for each possible texture
//
unsigned int lAttrIdx;
for (lAttrIdx = 0; lAttrIdx < lAttrList.size(); ++lAttrIdx)
{
osg::notify(osg::INFO) << "flt2osg::setMeshTexCoordinates() "
<< "Checking texture "
<< lAttrIdx
<< std::endl;
// If there aren't any coordinates for this texture, skip to next
//
if (!pool->hasAttribute ( lAttrList[lAttrIdx] ) )
continue;
// Allocate the vertices.
osg::Vec2Array *coords = new osg::Vec2Array(numVerts);
if ( NULL == coords )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshTexCoordinates out of memory."<<std::endl;
return;
}
osg::notify(osg::INFO) << "flt2osg::setMeshTexCoordinates() "
<< "Getting coords"
<< std::endl;
// Declare outside of loop.
uint32 i ( 0 ), index ( 0 );
float32 pu, pv;
// Loop through all the vertices.
for ( i = 0; i < numVerts; ++i )
{
// Get the i'th index into the vertex pool.
if ( !mesh->getVertexIndex ( i, index ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshTexCoordinates out of bounds."<<std::endl;
return;
}
// Get the coordinate (using "index").
if ( !pool->getUV ( index, lAttrList[lAttrIdx], pu, pv ) )
{
osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshTexCoordinates out of bounds."<<std::endl;
return;
}
// Add the coordinate.
(*coords)[i].set ( (float) pu, (float) pv );
}
osg::notify(osg::INFO) << "flt2osg::setMeshTexCoordinates() "
<< "Adding coords to texture unit "
<< lAttrIdx
<< std::endl;
// Set the mesh coordinates for this texture layer... use
// the attribute index as the texture unit.
//
geometry->setTexCoordArray ( lAttrIdx, coords );
} // check each possible texture
return;
}