// Modify ConvertFromFLT::setTexture to create a new osg::TexEnvCombiner in texture stateset to handle // detail texture // Julian Ortiz, June 18th 2003. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 "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 "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" 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; } 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."<getNumChildren(); i++) { Record* child = rec->getChild(i); if (!child->isAncillaryRecord()) break; switch (child->getOpcode()) { case LONG_ID_OP: visitLongID(osgPrimary, (LongIDRecord*)child); break; case MATRIX_OP: // Note: Ancillary record creates osg node parent = visitMatrix(*parent, osgPrimary, (MatrixRecord*)child); 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 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()) { 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, fr); else visitFace(&geoSetBuilder, fr); } break; case LIGHT_POINT_OP: visitLightPoint(&geoSetBuilder, (LightPointRecord*)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 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::Group& osgParent, CommentRecord* rec) { SComment *pSComment = (SComment*)rec->getData(); //std::cout << "ConvertFromFLT::visitComment '"<szComment,pSComment->RecHeader.length()-4)<<"'"<szComment<<"'"<szComment,rec->getBodyLength()); std::string commentfield(pSComment->szComment,stringLength); unsigned int front_of_line = 0; unsigned int end_of_line = 0; while (end_of_linegetData(); // Version _diOpenFlightVersion = pSHeader->diFormatRevLev; osg::notify(osg::INFO) << "Version " << _diOpenFlightVersion << std::endl; // Unit scale 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; } // 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("<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::visitGroup(osg::Group& osgParent, GroupRecord* rec) { SGroup* currentGroup = (SGroup*) rec->getData(); // OpenFlight 15.7 has two animation flags, forward and swing bool forwardAnim = (currentGroup->dwFlags & GroupRecord::FORWARD_ANIM)!=0; bool swingAnim = (currentGroup->dwFlags & GroupRecord::SWING_ANIM)!=0; if( forwardAnim || swingAnim ) { osg::Sequence* animSeq = new osg::Sequence; visitAncillary(osgParent, *animSeq, rec)->addChild( animSeq ); visitPrimaryNode(*animSeq, rec); if ( forwardAnim ) animSeq->setInterval(osg::Sequence::LOOP, 0, -1); else animSeq->setInterval(osg::Sequence::SWING, 0, -1); // 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 "<getName()<<" to group node."<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) osg::DOFTransform* transform = new osg::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<setMatrix(dof_matrix); return transform; #endif } osg::Group* ConvertFromFLT::visitSwitch(osg::Group& osgParent, SwitchRecord* rec) { SSwitch *pSSwitch = (SSwitch*)rec->getData(); osg::Switch* osgSwitch = new osg::Switch; 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."<getNumChildren()<<") "<getNumChildren()<<")"<nCurrentMask * pSSwitch->nWordsInMask + nChild / 32; if (nChildgetNumChildren()) { osgSwitch->setValue(nChild,(pSSwitch->aMask[nMaskWord] & (uint32(1) << nMaskBit))!=0); } } 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; 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 /*BIND_PERPRIM*/ ); 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 ); dgset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); break; case FaceRecord::VERTEX_COLOR_LIGHTING: // Use vertex color and vertex normal osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::ON ); dgset->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); dgset->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); break; default : osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); dgset->setColorBinding( osg::Geometry::BIND_OVERALL ); break; } } else // Version 11, 12 & 13 { osgStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); dgset->setColorBinding( osg::Geometry::BIND_OVERALL /*BIND_PERPRIM*/ ); } } void ConvertFromFLT::setColor ( FaceRecord *rec, SFace *pSFace, DynGeoSet *dgset, bool &bBlend ) { // // Face Color // if (pSFace->swTexWhite && (pSFace->iTexturePattern != -1)) { // Render textured polygons white _faceColor.set(1, 1, 1, 1); } else { ColorPool* pColorPool = rec->getFltFile()->getColorPool(); _faceColor.set(1, 1, 1, 1); if (rec->getFlightVersion() > 13) { if (!(pSFace->dwFlags & FaceRecord::NO_COLOR_BIT)) { bool bPackedColor = _bHdrRgbMode || (pSFace->dwFlags & FaceRecord::PACKED_COLOR_BIT) || (pColorPool == NULL); if (bPackedColor) _faceColor = pSFace->PrimaryPackedColor.get(); else { if (rec->getFlightVersion() >= 1540) { _faceColor = pColorPool->getColor(pSFace->dwPrimaryColorIndex); } else // Version 14.2, 15.0 { // The field now called wPrimaryNameIndex was // originally the primary color/intensity code // for OpenFlight v14.2 and v15.0 files _faceColor = pColorPool->getColor(pSFace->wPrimaryNameIndex); } } } } else // Version 11, 12 & 13 { bool bPackedColor = _bHdrRgbMode || (pColorPool == NULL); if (bPackedColor) _faceColor = pSFace->PrimaryPackedColor.get(); else _faceColor = pColorPool->getOldColor(pSFace->wPrimaryNameIndex); } } // Face color alpha _faceColor[3] = 1.0f - ((float)pSFace->wTransparency / 65535.0f); if (pSFace->wTransparency > 0) bBlend = true; if ((dgset->getColorBinding() == osg::Geometry::BIND_OVERALL) || (dgset->getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE)) dgset->addColor(_faceColor); } void ConvertFromFLT::setMaterial ( FaceRecord *rec, SFace *pSFace, osg::StateSet *osgStateSet, bool &bBlend ) { // // Material // MaterialPool* pMaterialPool = rec->getFltFile()->getMaterialPool(); if (pMaterialPool) { MaterialPool::PoolMaterial* pSMaterial = pMaterialPool->getMaterial((int)pSFace->iMaterial); if (pSMaterial) { osg::Material* osgMaterial = new osg::Material; osg::Vec4 ambient; osg::Vec4 diffuse; osg::Vec4 specular; osg::Vec4 emissiv; float alpha; // In contrast to the OpenFlight Specification this works! alpha = pSMaterial->sfAlpha * (1.0f - ((float)pSFace->wTransparency / 65535.0f)) * (1.0f - ((float)_wObjTransparency / 65535.0f)); ambient[0] = pSMaterial->Ambient[0] * _faceColor[0]; ambient[1] = pSMaterial->Ambient[1] * _faceColor[1]; ambient[2] = pSMaterial->Ambient[2] * _faceColor[2]; ambient[3] = alpha; diffuse[0] = pSMaterial->Diffuse[0] * _faceColor[0]; diffuse[1] = pSMaterial->Diffuse[1] * _faceColor[1]; diffuse[2] = pSMaterial->Diffuse[2] * _faceColor[2]; diffuse[3] = alpha; specular[0] = pSMaterial->Specular[0]; specular[1] = pSMaterial->Specular[1]; specular[2] = pSMaterial->Specular[2]; specular[3] = alpha; emissiv[0] = pSMaterial->Emissive[0]; emissiv[1] = pSMaterial->Emissive[1]; emissiv[2] = pSMaterial->Emissive[2]; emissiv[3] = alpha; osgMaterial->setColorMode(osg::Material::OFF); osgMaterial->setAmbient(osg::Material::FRONT_AND_BACK, ambient); osgMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); osgMaterial->setSpecular(osg::Material::FRONT_AND_BACK, specular); osgMaterial->setEmission(osg::Material::FRONT_AND_BACK, emissiv); osgMaterial->setAlpha(osg::Material::FRONT_AND_BACK, alpha); osgMaterial->setShininess(osg::Material::FRONT_AND_BACK, pSMaterial->sfShininess); osgStateSet->setAttribute(osgMaterial); if (alpha < 1.0f) bBlend = true; } } } void ConvertFromFLT::setTexture ( FaceRecord *rec, SFace *pSFace, osg::StateSet *osgStateSet, DynGeoSet *dgset, bool &bBlend ) { // // Texture // if (pSFace->iTexturePattern != -1) { TexturePool* pTexturePool = rec->getFltFile()->getTexturePool(); if (pTexturePool) { int nIndex = (int)pSFace->iTexturePattern; flt::AttrData *textureAttrData = pTexturePool->getTexture(nIndex,rec->getFlightVersion()); 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; if (pSFace->iDetailTexturePattern != -1) { int nIndex2 = (int)pSFace->iDetailTexturePattern; detailTextureAttrData = pTexturePool->getTexture(nIndex2,rec->getFlightVersion()); if (detailTextureAttrData && detailTextureAttrData->stateset) { osg::Texture2D *detTexture = dynamic_cast(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 ); } } //Now, an ugly thing,... we have detected that in Creator we defined that a texture will we used as //detail texture, and we load it as it using texture unit 1,... but we also need to create texture //coordinates to map this detail texture, I found that texture coordinates assigment is made in //DynGeoSet::addToGeometry and the easy way I found to create those new coordinates is to add a method //to DynGeoSet class named setDetailTextureStatus that pass detail Texture AttrData class, so when //DynGeoSet::addToGeometry runs it reads this class and create new texture coordinates if we got a valid //AttrData object. I now this is not a good way to do it, and I expect someone with more osg knowledge //could make it in a better way. // Julian Ortiz, June 18th 2003. if (pSFace->iDetailTexturePattern != -1 && detailTextureAttrData && detailTextureAttrData->stateset) dgset->setDetailTextureAttrData(detailTextureAttrData); else dgset->setDetailTextureAttrData(NULL); // Merge face stateset with texture stateset osgStateSet->merge(*textureStateSet); // Alpha channel in texture? osg::Texture2D *osgTexture = dynamic_cast(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."<(mtr->getData()); if (mt==0) { osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) mtr->getData() not valid SMultiTexture*."<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."< (pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFlightVersion())); CERR << "pTexturePool->getTexture((int)mt->data[l].texture): " << pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFlightVersion()) << "\n"; CERR << "textureStateSet: " << textureStateSet << "\n"; if (!textureStateSet) { CERR << "unable to set up multi-texture layer." << std::endl; return; } osg::Texture2D *texture = dynamic_cast(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."<setTextureAttributeAndModes( i, texture,osg::StateAttribute::ON); osg::TexEnv* osgTexEnv = new osg::TexEnv; CERR << "osgTexEnv: " << osgTexEnv << "\n"; osgTexEnv->setMode(osg::TexEnv::MODULATE); texture_stateset->setTextureAttribute( i, osgTexEnv ); CERR << "geom: " << geom << "\n"; CERR << ", referenceCount: " << geom->referenceCount() << "\n"; osg::StateSet* geom_stateset = geom->getStateSet(); CERR << "geom_stateset: " << geom_stateset << "\n"; if ( geom_stateset ) { geom_stateset->merge( *texture_stateset ); CERR << "Merging layer " << i << "\n"; } else { geom->setStateSet( texture_stateset ); CERR << "Setting layer " << i << "\n"; } l++; } } } void ConvertFromFLT::addUVList( DynGeoSet* dgset, UVListRecord* uvr ) { osg::Geometry* geom = dgset->getGeometry(); if (!geom || !uvr || !uvr->isAncillaryRecord()) { osg::notify(osg::WARN)<<"ConvertFromFLT::addUVList( DynGeoSet*, UVListRecord*) has been passed invalid paramters."<(uvr->getData()); if (!uvl) { osg::notify(osg::WARN)<<"ConvertFromFLT::addUVList( DynGeoSet*, UVListRecord*) uvr->getData() is invalid."<coordListSize(); for ( int i = 0; i < 8; i++ ) { if ( (1 << (32-i)) & uvl->layers ) { osg::Vec2Array* tcoords = new osg::Vec2Array; 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??? tcoords->push_back( osg::Vec2( uvl->coords.vertex[v].coords[1], uvl->coords.vertex[v].coords[0] ) ); } if ( !tcoords->empty() ) { CERR << "Setting tcoords " << i << ": " << tcoords << "\n"; geom->setTexCoordArray( i, tcoords ); } l++; } } } void ConvertFromFLT::visitFace(GeoSetBuilder* pBuilder, 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, rec); // Add face to builder pool pBuilder->addPrimitive(); // 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(child); if (!mtr) { osg::notify( osg::WARN ) << "flt::ConvertFromFLT::visitFace(GeoSetBuilder*, FaceRecord*) found invalid MultiTextureRecord*"<getDynGeoSet(), mtr ); } break; default: #ifdef _DEBUG osg::notify( osg::WARN ) << "flt::ConvertFromFLT::visitFace: " << "Unhandled opcode: " << child->getOpcode() << "\n"; #endif break; } } // Look for subfaces { _nSubfaceLevel++; int n; for(n=0; ngetNumChildren(); n++) { Record* child = rec->getChild(n); if (child && child->isOfType(FACE_OP)) visitFace(pBuilder, (FaceRecord*)child); } _nSubfaceLevel--; } } // Return number of vertices added to builder. int ConvertFromFLT::addVertices(GeoSetBuilder* pBuilder, PrimNodeRecord* primRec) { int i; int vertices=0; DynGeoSet* dgset = pBuilder->getDynGeoSet(); for(i=0; i < primRec->getNumChildren(); i++) { Record* child = primRec->getChild(i); if (child == NULL) break; switch (child->getOpcode()) { case VERTEX_LIST_OP: vertices += visitVertexList(pBuilder, (VertexListRecord*)child); break; case LOCAL_VERTEX_POOL_OP: vertices += visitLocalVertexPool(pBuilder, (LocalVertexPoolRecord *)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(); // 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(child); assert( uvr ); addUVList( dgset, uvr ); } break; case MULTI_TEXTURE_OP: { CERR2 << "MULTI_TEXTURE_OP in visitVertexList\n"; MultiTextureRecord* mtr = dynamic_cast(child); assert( mtr ); addMultiTexture( dgset, mtr ); } break; default: #ifdef _DEBUG osg::notify( osg::WARN ) << "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) { switch(rec->getOpcode()) { case VERTEX_C_OP: { SVertex* pVert = (SVertex*)rec->getData(); osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z()); coord *= (float)_unitScale; dgset->addCoord(coord); if (dgset->getColorBinding() == osg::Geometry::BIND_PER_VERTEX) ADD_VERTEX_COLOR(dgset, pVert, rec->getFltFile()->getColorPool()) } break; case VERTEX_CN_OP: { SNormalVertex* pVert = (SNormalVertex*)rec->getData(); osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z()); coord *= (float)_unitScale; 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: { SNormalTextureVertex* pVert = (SNormalTextureVertex*)rec->getData(); osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z()); coord *= (float)_unitScale; 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: { STextureVertex* pVert = (STextureVertex*)rec->getData(); osg::Vec3 coord(pVert->Coord.x(), pVert->Coord.y(), pVert->Coord.z()); coord *= (float)_unitScale; 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: { SOldVertex* pVert = (SOldVertex*)rec->getData(); osg::Vec3 coord(pVert->v[0], pVert->v[1], pVert->v[2]); coord *= (float)_unitScale; 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: { SOldVertexColor* pVert = (SOldVertexColor*)rec->getData(); osg::Vec3 coord(pVert->v[0], pVert->v[1], pVert->v[2]); coord *= (float)_unitScale; 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: { SOldVertexColorNormal* pVert = (SOldVertexColorNormal*)rec->getData(); osg::Vec3 coord(pVert->v[0], pVert->v[1], pVert->v[2]); coord *= (float)_unitScale; 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 : return 0; } return 1; } // 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) { // SExternalReference *pSExternal = (SExternalReference*)rec->getData(); osgDB::PushAndPopDataPath tmpfile(osgDB::getFilePath(rec->getFilename())); FltFile* pFile = rec->getExternal(); osg::Group* external = NULL; if (pFile) { external = pFile->convert(); if (external) visitAncillary(osgParent, *external, rec)->addChild(external); } return external; } void ConvertFromFLT::visitLightPoint(GeoSetBuilder* pBuilder, 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, rec); pBuilder->addPrimitive(); } 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, 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(child); assert( mtr ); addMultiTexture( dgset, mtr ); } break; default: #ifdef _DEBUG osg::notify( osg::WARN ) << "flt::ConvertFromFLT::visitMesh: " << "Unhandled opcode: " << child->getOpcode() << "\n"; #endif break; } } } int ConvertFromFLT::addMeshPrimitives ( osg::Group &parent, GeoSetBuilder *, 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, (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, MeshPrimitiveRecord *mesh ) { if ( !mesh ) { osg::notify(osg::NOTICE)<<"Warning:ConvertFromFLT::visitMeshPrimitive () mesh is 0, unable to process."<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: assert ( 0 ); // What type is this? return; } // Add the vertex properties. setMeshCoordinates ( mesh->getNumVertices(), pool, mesh, geometry ); setMeshNormals ( mesh->getNumVertices(), pool, mesh, geometry ); setMeshColors ( mesh->getNumVertices(), pool, mesh, geometry ); // 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 ) { assert ( pool ); assert ( mesh ); assert ( geometry ); // 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 ) { assert ( 0 ); 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 ) ) { assert ( 0 ); // We stepped out of bounds. break; } // Get the coordinate (using "index"). if ( !pool->getPosition ( index, px, py, pz ) ) { assert ( 0 ); // We stepped out of bounds. break; } // 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 ) { assert ( pool ); assert ( mesh ); assert ( geometry ); // 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 ) { assert ( 0 ); 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 ) ) { assert ( 0 ); // We stepped out of bounds. break; } // Get the normal (using "index"). if ( !pool->getNormal ( index, x, y, z ) ) { assert ( 0 ); // We stepped out of bounds. break; } // 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 ) { assert ( pool ); assert ( mesh ); assert ( geometry ); // 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 ) { assert ( 0 ); 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 ) ) { assert ( 0 ); // We stepped out of bounds. break; } // Get the color (using "index"). if ( false == pool->getColorRGBA ( index, red, green, blue, alpha ) ) { assert ( 0 ); // We stepped out of bounds. break; } // Add the coordinate. (*colors)[i].set ( red, green, blue, alpha ); } // Set the mesh coordinates. geometry->setColorArray ( colors ); // Return the number of colors added. return i; }