Files
OpenSceneGraph/src/osgPlugins/flt/flt2osg.cpp
2003-08-28 12:49:38 +00:00

2219 lines
71 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/Switch>
#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/DOFTransform>
#include <osg/Sequence>
#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 "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."<<std::endl;
return group;
}
osg::Group* ConvertFromFLT::visitAncillary(osg::Group& osgParent, osg::Group& osgPrimary, PrimNodeRecord* rec)
{
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 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 '"<<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
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("<<nIndex<<", "<<textureName<<")"<<std::endl;
}
/*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::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 "<<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)
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<<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();
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."<<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(unsigned int nChild=0; nChild<totalNumChildren; nChild++)
{
unsigned int nMaskBit = nChild % 32;
unsigned int nMaskWord = pSSwitch->nCurrentMask * pSSwitch->nWordsInMask + nChild / 32;
if (nChild<osgSwitch->getNumChildren())
{
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<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 );
}
}
//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<osg::Texture2D*>(textureStateSet->getTextureAttribute( 0, osg::StateAttribute::TEXTURE));
if (osgTexture)
{
osg::Image* osgImage = osgTexture->getImage();
if (getUseTextureAlphaForTransparancyBinning() && osgImage->isImageTranslucent()) bBlend = true;
}
#if 0 // Started to experiment with OpenFlight texture mapping modes
if (pSFace->iTextureMapIndex > -1)
{
osg::TexGen* osgTexGen = new osg::TexGen;
osgTexGen->setMode(osg::TexGen::SPHERE_MAP);
osgStateSet->setTextueAttributeAndModes( 0, osgTexGen,osg::StateAttribute::ON);
}
#endif
dgset->setTextureBinding(osg::Geometry::BIND_PER_VERTEX);
}
}
}
}
void ConvertFromFLT::setTransparency ( osg::StateSet *osgStateSet, bool &bBlend )
{
//
// Transparency
//
if (bBlend)
{
osg::BlendFunc* osgBlendFunc = new osg::BlendFunc();
osgBlendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
osgStateSet->setAttribute(osgBlendFunc);
osgStateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
osgStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}
}
void
ConvertFromFLT::addMultiTexture( DynGeoSet* dgset, MultiTextureRecord* mtr )
{
osg::Geometry* geom = dgset->getGeometry();
if (geom==0 || mtr==0 || !mtr->isAncillaryRecord())
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) has been passed invalid paramters."<<std::endl;
return;
}
SMultiTexture* mt = reinterpret_cast<SMultiTexture*>(mtr->getData());
if (mt==0)
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) mtr->getData() not valid SMultiTexture*."<<std::endl;
return;
}
CERR << "ConvertFromFLT::addMultiTexture\n";
int l = 0;
for ( int i = 0; i < 8; i++ )
{
if ( (1 << (32-i)) & mt->layers )
{
CERR << "Has layer " << i << "\n";
mt->data[l].endian();
CERR << "texture: " << mt->data[l].texture << "\n";
CERR << "effect: " << mt->data[l].effect << "\n";
CERR << "mapping: " << mt->data[l].mapping << "\n";
CERR << "data: " << mt->data[l].data << "\n";
TexturePool* pTexturePool = mtr->getFltFile()->getTexturePool();
assert( pTexturePool );
if (!pTexturePool)
{
osg::notify(osg::WARN)<<"ConvertFromFLT::addMultiTexture(DynGeoSet*, MultiTextureRecord*) pTexturePool invalid."<<std::endl;
return;
}
osg::StateSet *textureStateSet = dynamic_cast<osg::StateSet *> (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<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::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."<<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 )
{
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<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::WARN ) << "flt::ConvertFromFLT::visitFace: "
<< "Unhandled opcode: " << child->getOpcode() << "\n";
#endif
break;
}
}
// 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, (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<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::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<MultiTextureRecord*>(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."<<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;
}
assert ( pool );
// 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:
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;
}