Files
OpenSceneGraph/src/osgPlugins/flt/flt2osg.cpp
Robert Osfield 6b86d2d70d From Joson Daly, fix for forward/backward/swing animation handling both 15.8 and
versions prior to 15.8, and...

" Here's another fix for OpenFlight.  The symptom was that ATTR files were
not being read correctly, and the TexEnv on a texture that should have
been set to DECAL was instead defaulting to MODULATE.  The cause is that
the ATTR reader cannot tell by itself what version it's reading (the
version information isn't present in the ATTR files), and instead relies
on the ReaderWriter::Options passed in to get the OpenFlight version.

My change clones the current ReaderWriter::Options and prepends the
appropriate FLT_VER option before the ReaderWriterATTR object is
called.  I also made the parsing of the FLT_VER string and value more
robust in the ReaderWriterATTR itself.  I think I commented things OK,
but let me know if you need me to explain anything."
2005-04-14 07:55:45 +00:00

3351 lines
117 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 <osg/ProxyNode>
#include <osg/io_utils>
#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
#define USE_PROXYNODE_FOR_EXTERNAL_FILES
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();
// Check for forward animation (sequence)
bool forwardAnim = (currentGroup->dwFlags & GroupRecord::FORWARD_ANIM) != 0;
// For versions prior to 15.8, the swing bit can be set independently
// of the animation bit. This implies forward animation (with swing)
if ((fltVer < 1580) && (currentGroup->dwFlags & GroupRecord::SWING_ANIM))
forwardAnim = true;
// 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;
// Copy the current set of options
osg::ref_ptr<osgDB::ReaderWriter::Options> versionOptions =
(osgDB::ReaderWriter::Options*)rec->getFltFile()->
getOptions()->clone(osg::CopyOp(osg::CopyOp::SHALLOW_COPY));
// Create a new set of ReaderWriter options, and prepend the
// OpenFlight version option ("FLT_VER") and number to the current
// option string. This will inform the ATTR reader what version
// of OpenFlight file it's dealing with, so it knows how much data
// to read. (Unfortunately, this seems to be the only way to
// communicate with the ATTR reader from here).
char versionStr[30];
sprintf(versionStr, "FLT_VER %d ", rec->getFlightVersion());
std::string newString(versionStr);
newString.append(versionOptions->getOptionString());
versionOptions->setOptionString(newString);
// Finally, get the texture from the texture pool
flt::AttrData *textureAttrData =
pTexturePool->getTexture(nIndex, versionOptions.get());
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,versionOptions.get());
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;
}
// Copy the current set of options
osg::ref_ptr<osgDB::ReaderWriter::Options> versionOptions =
(osgDB::ReaderWriter::Options*)mtr->getFltFile()->
getOptions()->clone(osg::CopyOp(osg::CopyOp::SHALLOW_COPY));
// Create a new set of ReaderWriter options, and prepend the
// OpenFlight version option ("FLT_VER") and number to the current
// option string. This will inform the ATTR reader what version
// of OpenFlight file it's dealing with, so it knows how much data
// to read. (Unfortunately, this seems to be the only way to
// communicate with the ATTR reader from here).
char versionStr[30];
sprintf(versionStr, "FLT_VER %d ", mtr->getFlightVersion());
std::string newString(versionStr);
newString.append(versionOptions->getOptionString());
versionOptions->setOptionString(newString);
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,versionOptions.get()));
CERR << "pTexturePool->getTexture((int)mt->data[l].texture): " << pTexturePool->getTexture((int)mt->data[l].texture,versionOptions.get()) << "\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)
{
//Path for Nested external references
osgDB::ReaderWriter::Options *options = pFile->getOptions();
#ifdef USE_PROXYNODE_FOR_EXTERNAL_FILES
if(options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)
{
external = dynamic_cast<osg::Group*> (osgDB::Registry::instance()->getFromObjectCache(rec->getFilename()));
if(external)
{
osg::Group *tempParent = visitAncillary(osgParent, *external, rec);
tempParent->addChild(external);
return external;
}
}
#endif
osgDB::FilePathList& fpl = options->getDatabasePathList();
const std::string& filePath = osgDB::getFilePath(rec->getFilename());
std::string pushAndPopPath;
//If absolute path
if( (filePath.length()>0 && filePath.find_first_of("/\\")==0) ||
(filePath.length()>2 && filePath.substr(1,1)==":" && filePath.find_first_of("/\\")==2) )
{
pushAndPopPath = filePath;
}
else
{
pushAndPopPath = (fpl.empty() | fpl.back().empty() ? "." : fpl.back()) + "/" + filePath;
}
fpl.push_back(pushAndPopPath);
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() )
{
#ifdef USE_PROXYNODE_FOR_EXTERNAL_FILES
// Add the entire externally referenced file
osg::ProxyNode *proxynode = new osg::ProxyNode;
proxynode->setCenterMode(osg::ProxyNode::USE_BOUNDING_SPHERE_CENTER);
proxynode->addChild(external, rec->getFilename());
tempParent->addChild(proxynode);
if(options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)
osgDB::Registry::instance()->addEntryToObjectCache(rec->getFilename(), proxynode);
#else
tempParent->addChild(external);
#endif
}
else
{
// Find the specified model
FindExternalModelVisitor findExternalModelVisitor;
findExternalModelVisitor.setModelName( modelName );
external->accept( findExternalModelVisitor );
osg::Node *model = findExternalModelVisitor.getModel();
if (model)
{
#ifdef USE_PROXYNODE_FOR_EXTERNAL_FILES
osg::ProxyNode *proxynode = new osg::ProxyNode;
proxynode->setCenterMode(osg::ProxyNode::USE_BOUNDING_SPHERE_CENTER);
proxynode->addChild(model, rec->getFilename());
tempParent->addChild(proxynode);
if(options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)
osgDB::Registry::instance()->addEntryToObjectCache(rec->getFilename(), proxynode);
#else
//tempParent->addChild(model);
#endif
}
else
{
osg::notify(osg::WARN) << "In ConvertFromFLT::visitExternal,"
<< " the requested model " << modelName
<< " was not found in external file "
<< rec->getFilename() << std::endl;
}
}
}
fpl.pop_back();
}
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;
}