Fixes for IRIX and Boris Bralo's TerraPage loader.

This commit is contained in:
Robert Osfield
2002-02-08 09:30:02 +00:00
parent 62d8b1e8de
commit 4c5fcd3f61
45 changed files with 11037 additions and 11 deletions

View File

@@ -0,0 +1,533 @@
/* **************************************************************************
* OpenSceneGraph loader for Terrapage format database
* by Boris Bralo 2002
*
* based on/modifed sgl (Scene Graph Library) loader by Brian Walsh
*
* This loader is based on/modified from Terrain Experts Performer Loader,
* and was ported to SGL by Bryan Walsh / bryanw at earthlink dot net
*
* That loader is redistributed under the terms listed on Terrain Experts
* website (www.terrex.com/www/pages/technology/technologypage.htm)
*
* "TerraPage is provided as an Open Source format for use by anyone...
* We supply the TerraPage C++ source code free of charge. Anyone
* can use it and redistribute it as needed (including our competitors).
* We do, however, ask that you keep the TERREX copyrights intact."
*
* Copyright Terrain Experts Inc. 1999.
* All Rights Reserved.
*
*****************************************************************************/
#include "trpage_sys.h"
#include <osg/Group>
#include <osg/Material>
#include <osg/Texture>
#include <osg/TexEnv>
#include <osg/LOD>
#include <osg/Geode>
#include <osg/Billboard>
#include <osg/Matrix>
#include <osg/Transform>
#include <osg/GeoSet>
#include <osg/CullFace>
#include <osg/Light>
#include <osg/Transparency>
#include <osg/Notify>
#include "TrPageParser.h"
/*
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
*/
#include <algorithm>
using namespace txp;
using namespace osg;
using std::vector;
using std::string;
geomRead::geomRead(TrPageParser *in_parse)
{
parse = in_parse;
}
geomRead::~geomRead()
{
}
void* geomRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgGeometry geom;
if (!geom.Read(buf))
return NULL;
// Get the necessary info out of the geom
trpgGeometry::PrimType primType;
int numPrims;
int numVert;
int numNorm;
int matId;
geom.GetPrimType(primType);
geom.GetNumPrims(numPrims);
geom.GetNumVertex(numVert);
numVert /= 3;
geom.GetMaterial(0,matId);
geom.GetNumNormal(numNorm);
numNorm /= 3;
Vec3* vertices = new Vec3[numVert];
// Get vertices
// it can be done this way because standard guaranties that vector is on
// continuous storage and vec3 is POD
geom.GetVertices((float32 *)vertices);
// Turn the trpgGeometry into something Performer can understand
GeoSet *gset = 0L;
// Get texture coordinates
Vec2* tex_coords = 0L;
trpgTexData td;
if (geom.GetTexCoordSet(0,&td))
{
tex_coords = new Vec2[numVert];
for (int i=0 ;i < numVert; i++)
{
tex_coords[i][0] = td.floatData[2*i+0];
tex_coords[i][1] = td.floatData[2*i+1];
}
}
Vec3* normals = 0L;
if (numNorm == numVert)
{
normals = new Vec3[numVert];
geom.GetNormals((float32 *)normals);
}
Geode *geode = new Geode();
// Set up the primitive type
switch (primType)
{
case trpgGeometry::Triangles:
{
gset = new GeoSet;
gset->setPrimType(GeoSet::TRIANGLES);
}
break;
case trpgGeometry::TriStrips:
{
// Need primitive lengths too
int* primitives = new int[numPrims];
geom.GetPrimLengths(primitives);
// Define GeoSet
gset = new GeoSet;
gset->setPrimType(GeoSet::TRIANGLE_STRIP);
gset->setPrimLengths(primitives);
}
break;
case trpgGeometry::TriFans:
{
// Need primitive lengths too
int* primitives = new int[numPrims];
geom.GetPrimLengths(primitives);
// Need to flip the fans
int ind = 0;
for (int i=0;i<numPrims;i++)
{
int start=ind+1;
int end=primitives[i]+ind-1;
// Swap from start+1 to end
int numSwap = (end-start+1)/2;
// Swap vertices, texture coords & normals
for (int j=0; j < numSwap; j++ )
{
std::swap(vertices[start], vertices[end]);
if( tex_coords )
std::swap(tex_coords[start], tex_coords[end]);
if(normals)
std::swap(normals[start], normals[end]);
start++;
end--;
}
ind += primitives[i];
}
// Define GeoSet
gset = new GeoSet;
gset->setPrimType(GeoSet::TRIANGLE_FAN);
gset->setPrimLengths(primitives);
}
break;
default:
break;
};
// Add it to the current parent group
Group *top = parse->GetCurrTop();
if (gset)
{
gset->setCoords(vertices);
gset->setNumPrims(numPrims);
if (normals)
gset->setNormals(normals);
// Note: Should check number of materials first
// Note: Should be combining multiple geosets
StateSet* sset = (*parse->GetMaterials())[matId].get();
if (tex_coords)
{
gset->setTextureCoords(tex_coords);
gset->setTextureBinding(GeoSet::BIND_PERVERTEX);
}
gset->setStateSet(sset);
geode->addDrawable(gset);
top->addChild(geode);
}
return (void *) 1;
}
//
// Group Reader Class
//
//----------------------------------------------------------------------------
groupRead::groupRead(TrPageParser *in_parse)
{
parse = in_parse;
}
//----------------------------------------------------------------------------
void* groupRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgGroup group;
if (!group.Read(buf))
return NULL;
// Create a new Performer group
Group *osg_Group = new Group();
// Dump this group into the hierarchy
Group *top = parse->GetCurrTop();
if (top)
top->addChild(osg_Group);
int32 id;
group.GetID(id);
parse->AddToGroupList(id,osg_Group);
return (void *) osg_Group;
}
//----------------------------------------------------------------------------
//
// Attach Reader Class
//
attachRead::attachRead(TrPageParser *in_parse)
{
parse = in_parse;
}
//----------------------------------------------------------------------------
void* attachRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgAttach group;
if (!group.Read(buf))
return NULL;
// Create a new Performer group
Group *osg_Group = new Group();
// Dump this group into the hierarchy
Group *top = parse->GetCurrTop();
if (top)
top->addChild(osg_Group);
int32 id;
group.GetID(id);
parse->AddToGroupList(id,osg_Group);
// This sets the parent ID for the current tile too
int32 parentID;
group.GetParentID(parentID);
parse->SetParentID(parentID);
return (void *) osg_Group;
}
//----------------------------------------------------------------------------
//
// Billboard Reader Class
//
billboardRead::billboardRead(TrPageParser *in_parse)
{
parse = in_parse;
}
//----------------------------------------------------------------------------
void* billboardRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgBillboard bill;
if (!bill.Read(buf))
return NULL;
Group* osg_Group = new Group;
int type;
bill.GetType(type);
if( type == trpgBillboard::Group )
{
// Create a new Performer group
Billboard* bl = new Billboard();
int m;
bill.GetMode(m);
if( m = trpgBillboard::Eye)
bl->setMode(Billboard::POINT_ROT_EYE);
else if(m == trpgBillboard::World )
bl->setMode(Billboard::POINT_ROT_WORLD);
else if(m == trpgBillboard::Axial )
{
trpg3dPoint p;
bill.GetAxis(p);
bl->setAxis(Vec3(p.x, p.y, p.z));
bl->setMode(Billboard::AXIAL_ROT);
}
osg_Group->addChild(bl);
}
// Dump this group into the hierarchy
Group *top = parse->GetCurrTop();
if (top)
top->addChild(osg_Group);
int32 id;
bill.GetID(id);
parse->AddToGroupList(id,osg_Group);
return (void *) osg_Group;
}
//----------------------------------------------------------------------------
//
// LOD Reader Class
//
lodRead::lodRead (TrPageParser *in_parse)
{
parse = in_parse;
}
//----------------------------------------------------------------------------
void* lodRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgLod lod;
if (!lod.Read(buf))
return NULL;
// Pull out the LOD data we'll need
trpg3dPoint center;
lod.GetCenter(center);
double in,out,width;
lod.GetLOD(in,out,width);
double minRange = MIN(in,out);
double maxRange = MAX(in,out);
// Create a new Performer LOD
LOD *osg_Lod = new LOD();
Vec3 osg_Center;
osg_Center[0] = center.x; osg_Center[1] = center.y; osg_Center[2] = center.z;
osg_Lod->setCenter(osg_Center);
osg_Lod->setRange(0,minRange);
osg_Lod->setRange(1,maxRange);
// Our LODs are binary so we need to add a group under this LOD and attach stuff
// to that instead of the LOD
Group *osg_LodG = new Group();
osg_Lod->addChild(osg_LodG);
// Dump this group into the hierarchy
Group *top = parse->GetCurrTop();
if (top)
top->addChild(osg_Lod);
int32 id;
lod.GetID(id);
// Add the sub-group to the group list, not the LOD
parse->AddToGroupList(id,osg_LodG);
return (void *) osg_LodG;
}
//----------------------------------------------------------------------------
//
// Model Reference Reader Class
//
modelRefRead::modelRefRead(TrPageParser *in_parse)
{
parse = in_parse;
}
//----------------------------------------------------------------------------
void *modelRefRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgModelRef model;
if (!model.Read(buf))
return NULL;
// Get the matrix and pfNode for the model
int modelID;
model.GetModel(modelID);
float64 mat[16];
model.GetMatrix(mat);
Matrix osg_Mat(
(float)mat[0], (float)mat[1], (float)mat[2], (float)mat[3],
(float)mat[4], (float)mat[5], (float)mat[6], (float)mat[7],
(float)mat[8], (float)mat[9], (float)mat[10],(float)mat[11],
(float)mat[12],(float)mat[13],(float)mat[14],(float)mat[15]
);
// Note: Array check before you do this
Node *osg_Model = (*parse->GetModels())[modelID].get();
// Create the SCS and position the model
if (osg_Model) {
Transform *scs = new Transform();
scs->setMatrix(osg_Mat);
scs->addChild(osg_Model);
// Add the SCS to the hierarchy
Group *top = parse->GetCurrTop();
if (top)
top->addChild(scs);
}
return (void *) 1;
}
//----------------------------------------------------------------------------
//
// Tile Header Reader Class
//
tileHeaderRead::tileHeaderRead(TrPageParser *in_parse)
{
parse = in_parse;
}
//----------------------------------------------------------------------------
void* tileHeaderRead::Parse(trpgToken /*tok*/,trpgReadBuffer &buf)
{
trpgTileHeader *tileHead = parse->GetTileHeaderRef();
if (!tileHead->Read(buf))
return NULL;
return (void *) 1;
}
/* ********************************** */
//----------------------------------------------------------------------------
// Constructor for scene graph parser
TrPageParser::TrPageParser()
{
currTop = NULL;
top = NULL;
// Register the readers
AddCallback(TRPG_GEOMETRY,new geomRead(this));
AddCallback(TRPG_GROUP,new groupRead(this));
AddCallback(TRPG_ATTACH,new attachRead(this));
AddCallback(TRPG_BILLBOARD,new billboardRead(this));
AddCallback(TRPG_LOD,new lodRead(this));
AddCallback(TRPG_MODELREF,new modelRefRead(this));
AddCallback(TRPGTILEHEADER,new tileHeaderRead(this));
}
//----------------------------------------------------------------------------
// Destructor for scene graph parser
TrPageParser::~TrPageParser()
{
}
//----------------------------------------------------------------------------
// Return a reference to the Tile Header
// Doesn't do much if you haven't just read a tile
trpgTileHeader *TrPageParser::GetTileHeaderRef()
{
return &tileHead;
}
//----------------------------------------------------------------------------
// Parse a buffer and return a (chunk of) Performer
// scene graph.
Group *TrPageParser::ParseScene(trpgReadBuffer &buf,vector<ref_ptr<StateSet> > &in_mat,vector<ref_ptr<Node> > &in_model)
{
top = currTop = new Group();
materials = &in_mat;
models = &in_model;
parentID = -1;
// All the setup is handled in the constructor.
// Just parse and return the top
if (!Parse(buf))
{
notify(WARN) << "trpgFPParser::ParseScene failed to parse tile.\n";
return NULL;
}
Group *ret = top;
top = currTop = NULL;
return ret;
}
//----------------------------------------------------------------------------
// Start Children
// This is called when the parser hits a push.
// We'll want to make the node it's handing us the "top" node
bool TrPageParser::StartChildren(void *in_node)
{
Group *node = (Group *)in_node;
currTop = node;
return true;
}
//----------------------------------------------------------------------------
// This is called when the parser hits a pop.
// We'll want to look on the parent list (in trpgSceneParser)
// for the parent above the current one.
// If there isn't one, we'll just stick things in our top group.
bool TrPageParser::EndChildren(void * /* in_node */)
{
// Get the parent above the current one
int pos = parents.size()-2;
if (pos < 0)
{
// Nothing above the current one. Fall back on our top group
currTop = top;
}
else
{
currTop = (Group *)parents[pos];
}
return true;
}
//----------------------------------------------------------------------------
// Return the current top node
Group *TrPageParser::GetCurrTop()
{
if (currTop)
{
return currTop;
}
else
{
return top;
}
}
//----------------------------------------------------------------------------
// Add the given pfGroup to the group list at position ID
bool TrPageParser::AddToGroupList(int ID,Group *group)
{
// Note: check bounds
groupList[ID] = group;
return true;
}
//----------------------------------------------------------------------------
// Initialize the group list
void TrPageParser::SetMaxGroupID(int maxGroupID)
{
notify(WARN) << "trpgFPParser: max group ID = " << maxGroupID << std::endl;
// Initialize the group list with -1's
groupList.resize(0);
// Note: Fix this
for (int i=0;i<maxGroupID;i++)
groupList.push_back(NULL);
}