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

@@ -83,6 +83,9 @@ Paul Fredrikson
Phil Atkin <philatkin@philatkin.com>
- MacOS X port.
Boris Bralo
- txp TerraPage loader.
Sasa Bistrivic <sasa.bistrovic@zg.hinet.hr>
- option for detailed calculation of the near clipping plane during cull traversal.

View File

@@ -6,7 +6,11 @@ DIRS = src
VERSION = osg-0.8.43
export OSGHOME := $(shell pwd)
ifeq (IRIX|IRIX64,true)
export OSGHOME = `pwd`
else
export OSGHOME := $(shell pwd)
endif
all : $(MAKE_PREP)
for f in $(DIRS) ; do cd $$f; $(MAKE) || exit 1; cd ..; done

View File

@@ -96,6 +96,24 @@ Package=<4>
###############################################################################
Project: "txp"=".\osgPlugins\txp\txp.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name osg
End Project Dependency
Begin Project Dependency
Project_Dep_Name osgDB
End Project Dependency
}}}
###############################################################################
Project: "gif"=".\osgPlugins\gif\gif.dsp" - Package Owner=<4>
Package=<5>

View File

@@ -0,0 +1,215 @@
# Microsoft Developer Studio Project File - Name="txp" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=txp - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "txp.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "txp.mak" CFG="txp - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "txp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "txp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "txp - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TXP_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TXP_EXPORTS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x41a /d "NDEBUG"
# ADD RSC /l 0x41a /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../../bin/osgdb_txp.dll"
!ELSEIF "$(CFG)" == "txp - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "../../../lib"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TXP_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /vmg /vd0 /GR /GX /Zi /Od /I "../../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TXP_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x41a /d "_DEBUG"
# ADD RSC /l 0x41a /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 osgd.lib osgdbd.lib /nologo /dll /debug /machine:I386 /out:"../../../bin/osgdb_txpd.dll" /pdbtype:sept /libpath:"f:/osgcvs/openscenegraph/lib/"
!ENDIF
# Begin Target
# Name "txp - Win32 Release"
# Name "txp - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\ReaderWriterTXP.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_basic.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_geom.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_header.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_material.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_model.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_nodes.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_parse.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_rarchive.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_readbuf.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_swap.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_tile.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_warchive.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_writebuf.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TrPageArchive.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TrPageParser.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\ReaderWriterTXP.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trdll.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_geom.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_ident.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_io.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_read.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_scene.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_swap.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_sys.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\trpage_write.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TrPageArchive.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TrPageParser.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@@ -83,7 +83,7 @@ class SG_EXPORT Billboard : public Geode
struct ComputeBillboardCallback : public osg::Referenced
{
/** Get the transformation matrix which moves from local coords to world coords.*/
virtual void computeMatrix(const Matrix& matrix, const Billboard* billboard, const Vec3& eye_local, const Vec3& up_local, const Vec3& pos_local) const;
virtual const bool computeMatrix(const Matrix& matrix, const Billboard* billboard, const Vec3& eye_local, const Vec3& up_local, const Vec3& pos_local) const;
};
friend struct osg::Billboard::ComputeBillboardCallback;
@@ -99,7 +99,7 @@ class SG_EXPORT Billboard : public Geode
const ComputeBillboardCallback* getComputeBillboardCallback() const { return _computeBillboardCallback.get(); }
inline void getMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3& up_local, const Vec3& pos_local) const
inline const bool getMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3& up_local, const Vec3& pos_local) const
{
if (_computeBillboardCallback.valid())
return _computeBillboardCallback->computeMatrix(matrix,this,eye_local,up_local,pos_local);
@@ -113,7 +113,7 @@ class SG_EXPORT Billboard : public Geode
virtual const bool computeBound() const;
virtual void computeMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3& up_local, const Vec3& pos_local) const;
virtual const bool computeMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3& up_local, const Vec3& pos_local) const;
enum AxisAligned
{

View File

@@ -79,6 +79,7 @@ class SG_EXPORT Statistics : public osg::Referenced, public osg::Drawable::Attri
primverts[0] += (end-begin);
return true;
}
return false;
}
void addNumPrims(const int typ, const int nprimlen, const int numprimtype, const int primvert)

View File

@@ -28,7 +28,7 @@ namespace osgGLUT
* but shouldn't be viewed as the be all and end of osg viewer classes.
* Someone please rewrite it :-)
*/
class OSGGLUT_EXPORT Viewer : public Window, osgUtil::GUIActionAdapter
class OSGGLUT_EXPORT Viewer : public Window, public osgUtil::GUIActionAdapter
{
public:

View File

@@ -52,7 +52,7 @@ class OSGTEXT_EXPORT Font : public osg::Object
Font();
Font(const Font& font,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
Object(font,copyop),
osg::Object(font,copyop),
_init(false),
_created(false),
_font(0L),

View File

@@ -28,7 +28,7 @@ class OSGUTIL_EXPORT RenderStage : public RenderBin
RenderStage();
virtual osg::Object* cloneType(const osg::CopyOp&) const { return new RenderStage(); }
virtual osg::Object* cloneType() const { return new RenderStage(); }
virtual osg::Object* clone(const osg::CopyOp&) const { return new RenderStage(); } // note only implements a clone of type.
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const RenderStage*>(obj)!=0L; }
virtual const char* className() const { return "RenderStage"; }

View File

@@ -98,7 +98,7 @@ const bool Billboard::removeDrawable( Drawable *gset )
return false;
}
void Billboard::computeMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3& /*up_local*/, const Vec3& pos_local) const
const bool Billboard::computeMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3& /*up_local*/, const Vec3& pos_local) const
{
Vec3 ev(pos_local-eye_local);
@@ -161,6 +161,8 @@ void Billboard::computeMatrix(Matrix& matrix, const Vec3& eye_local, const Vec3&
matrix.setTrans(pos_local);
return true;
}
const bool Billboard::computeBound() const

View File

@@ -1,7 +1,7 @@
#include <osgDB/FileNameUtils>
#if defined(__sgi)
#include <cctype.h>
#include <ctype.h>
#elif !defined(WIN32)
#include <cctype>
using std::tolower;

View File

@@ -1,7 +1,7 @@
#!smake
SHELL=/bin/sh
DIRS = osg rgb lib3ds flt obj lwo dw bmp pic tga osgtgz tgz zip
DIRS = osg rgb lib3ds flt obj lwo txp dw bmp pic tga osgtgz tgz zip
# comment in if you have Performer installed.
# DIRS += pfb

View File

@@ -0,0 +1,38 @@
#!smake
include $(OSGHOME)/Make/makedefs
C++FILES = \
ReaderWriterTXP.cpp\
TrPageArchive.cpp\
TrPageParser.cpp\
trpage_basic.cpp\
trpage_geom.cpp\
trpage_header.cpp\
trpage_tile.cpp\
trpage_readbuf.cpp\
trpage_rarchive.cpp\
trpage_writebuf.cpp\
trpage_warchive.cpp\
trpage_parse.cpp\
trpage_nodes.cpp\
trpage_model.cpp\
trpage_material.cpp\
TARGET_BASENAME = osgdb_txp
TARGET_LIB_FILES = lib$(TARGET_BASENAME).$(DL_EXT)
LIB =
LOADABLE = $(OSGHOME)/lib/osgPlugins/$(TARGET_BASENAME).$(DL_EXT)
TARGET_LOADER_FILES = osgPlugins/$(TARGET_BASENAME).$(DL_EXT)
LIBS = $(GL_LIBS) -losg -losgDB
MACOSXLIBS = -L$(OSGHOME)/lib -losg -losgDB -lstdc++
C++FLAGS += -I. -I$(OSGHOME)/include
LDFLAGS += -L$(OSGHOME)/lib
include $(OSGHOME)/Make/makerules

View File

@@ -0,0 +1,93 @@
#include "ReaderWriterTXP.h"
#include "TrPageArchive.h"
#include <osg/Group>
#include <osg/Object>
#include <osg/Node>
#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <iostream>
using namespace txp;
using namespace osg;
//----------------------------------------------------------------------------
// private class for txp file
class TXPFile
{
public:
TrPageArchive archive;
TXPFile()
{
};
~TXPFile()
{
};
Node* readNode(const string &filename)
{
Group* ret = 0;
// search the SGL data path
string foundname = osgDB::findFile(filename.c_str());
if( !foundname.empty())
{
if (archive.OpenFile(foundname))
{
notify(INFO) << "TXPFile::loadFile(): loading archive: "
<< foundname << std::endl;
archive.LoadMaterials();
archive.LoadModels();
notify(INFO) << "TXPFile::loadFile(): loading geometry"
<< std::endl;
ret = new Group;
ret->addChild(archive.LoadAllTiles());
notify(INFO) << "TXPFile::loadFile(): loaded archive: "
<< foundname << std::endl;
//sgluOutputTree(sceneGraph, cout, 3);
}
else
{
notify(WARN) << "Failed to load archive: " << foundname << std::endl;
}
}
else
{
notify(WARN) <<"sglTrPageGroup::loadFile() failed to find archive: "
<< foundname << std::endl;
}
return ret;
};
Object* readObject(const string &filename)
{
return readNode(filename);
};
};
osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readObject(const std::string& fileName, const osgDB::ReaderWriter::Options*)
{
TXPFile read;
Object* obj = read.readObject(fileName);
if (obj) return obj;
else return ReadResult::FILE_NOT_HANDLED;
}
osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*)
{
TXPFile read;
Node* node = read.readNode(fileName);
if (node) return node;
else return ReadResult::FILE_NOT_HANDLED;
}
osgDB::RegisterReaderWriterProxy<ReaderWriterTXP> g_txpReaderWriterProxy;

View File

@@ -0,0 +1,50 @@
/*****************************************************************************
* Reader for Terrex TerraPage File format for OpenSceneGraph Library
*
* Copyright (C) 2002 Boris Bralo All Rights Reserved.
*
* based on code from Scene Graph Library:
* Copyright (C) Bryan Walsh All Rights Reserved.
* and Terrex
* Copyright Terrain Experts Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#ifndef READER_WRITER_TXP_H
#define READER_WRITER_TXP_H
#include "trpage_sys.h"
#include <osg/Object>
#include <osg/Node>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
namespace txp
{
class ReaderWriterTXP : public osgDB::ReaderWriter
{
public:
virtual const char* className() { return "TXP Reader/Writer"; }
virtual bool acceptsExtension(const std::string& extension)
{
return osgDB::equalCaseInsensitive(extension,"txp");
}
virtual ReadResult readObject(const std::string& fileName, const osgDB::ReaderWriter::Options*);
virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*);
};
}; // namespace
#endif

View File

@@ -0,0 +1,358 @@
#include "TrPageArchive.h"
#include "TrPageParser.h"
#include <osg/Group>
#include <osg/Image>
#include <osg/Texture>
#include <osg/Material>
#include <osg/TexEnv>
#include <osg/Transparency>
#include <osg/CullFace>
#include <osg/Light>
#include <osg/StateSet>
#include <osg/Notify>
#include <osgDB/FileUtils>
#include <iostream>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include "trpage_geom.h"
#include "trpage_read.h"
#include "trpage_write.h"
#include "trpage_scene.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace txp;
using namespace osg;
TrPageArchive::TrPageArchive()
: trpgr_Archive()
, parse(new TrPageParser())
{
}
TrPageArchive::~TrPageArchive()
{
}
bool TrPageArchive::OpenFile(const string &file)
{
m_alternate_path = osgDB::getFilePath(file);
std::string name = osgDB::getSimpleFileName(file);
if(m_alternate_path.empty())
SetDirectory(".");
else
{
osgDB::setFilePath(m_alternate_path.c_str());
SetDirectory(m_alternate_path.c_str());
}
if (!trpgr_Archive::OpenFile(name.c_str()))
{
notify(WARN) << "TrPageArchive::OpenFile() error: "
<< "couldn't open archive: " << file << std::endl;
return false;
}
if (!ReadHeader())
{
notify(WARN) << "TrPageArchive::OpenFile() error: "
<< "couldn't read header for archive: " << file
<< std::endl;
return false;
}
// Set the max group ID here because it won't change
const trpgHeader *head = GetHeader();
int maxID;
head->GetMaxGroupID(maxID);
parse->SetMaxGroupID(maxID);
return true;
}
// load textures and materials
// TODO : multitexturing
void TrPageArchive::LoadMaterials()
{
int n_textures;
texTable.GetNumTextures(n_textures);
m_textures.resize(n_textures);
// these extra braces are workaroud for annoying bug in MSVC
// for( int i = ....) and i is visible outside the loop
{
for (int i=0; i < n_textures ; i++)
{
trpgTexture *tex;
tex = texTable.GetTextureRef(i);
char texName[1024]; texName[0] = 0;
tex->GetName(texName,1023);
// Create a texture by name.
Texture *osg_texture = new Texture();
// Load Texture and Create Texture State
std::string filename = osgDB::getSimpleFileName(texName);
std::string path(getDir());
std::string theFile = path + '/'+ filename ;
ref_ptr<Image> image = osgDB::readImageFile(theFile);
if (image.valid())
{
osg_texture->setImage(image.get());
}
m_textures[i] = osg_texture;
}
}
// create materials
int n_materials;
materialTable.GetNumMaterial(n_materials);
{
for (int i = 0; i < n_materials; i++)
{
StateSet* osg_state_set = new StateSet;
trpgMaterial *mat;
mat = materialTable.GetMaterialRef(0,i);
// Set texture
int numMatTex;
mat->GetNumTexture(numMatTex);
// TODO : multitextuting
// also note that multitexturing in terrapage can came from two sides
// - multiple textures per material, and multiple materials per geometry
if(numMatTex)
{
int texId;
trpgTextureEnv texEnv;
mat->GetTexture(0,texId,texEnv);
// Set up texture environment
TexEnv *osg_texenv = new TexEnv();
int32 te_mode;
texEnv.GetEnvMode(te_mode);
switch( te_mode )
{
case trpgTextureEnv::Alpha :
osg_texenv->setMode(TexEnv::REPLACE);
break;
case trpgTextureEnv::Decal:
osg_texenv->setMode(TexEnv::DECAL);
break;
case trpgTextureEnv::Blend :
osg_texenv->setMode(TexEnv::BLEND);
break;
case trpgTextureEnv::Modulate :
osg_texenv->setMode(TexEnv::MODULATE);
break;
}
osg_state_set->setAttribute(osg_texenv);
Material *osg_material = new Material;
float64 alpha;
mat->GetAlpha(alpha);
trpgColor color;
mat->GetAmbient(color);
osg_material->setAmbient( Material::FRONT_AND_BACK ,
Vec4(color.red, color.green, color.blue, alpha));
mat->GetDiffuse(color);
osg_material->setDiffuse(Material::FRONT_AND_BACK ,
Vec4(color.red, color.green, color.blue, alpha));
mat->GetSpecular(color);
osg_material->setSpecular(Material::FRONT_AND_BACK ,
Vec4(color.red, color.green, color.blue, alpha));
mat->GetEmission(color);
osg_material->setEmission(Material::FRONT_AND_BACK ,
Vec4(color.red, color.green, color.blue, alpha));
float64 shinines;
mat->GetShininess(shinines);
osg_material->setShininess(Material::FRONT_AND_BACK , (float)shinines/128.0);
osg_material->setAlpha(Material::FRONT_AND_BACK ,(float)alpha);
osg_state_set->setAttributeAndModes(osg_material, StateAttribute::ON);
if( alpha < 1.0f )
{
osg_state_set->setMode(GL_BLEND,StateAttribute::ON);
osg_state_set->setRenderingHint(StateSet::TRANSPARENT_BIN);
}
/*
int alphaFunc;
mat->GetAlphaFunc(alphaFunc);
*/
// transparency
Transparency *osg_transparency = new Transparency;
osg_transparency->setFunction(Transparency::SRC_ALPHA, Transparency::ONE_MINUS_SRC_ALPHA);
osg_state_set->setAttributeAndModes(osg_transparency, StateAttribute::ON);
int wrap_s, wrap_t;
texEnv.GetWrap(wrap_s, wrap_t);
Texture* osg_texture = m_textures[texId].get();
osg_texture->setWrap(Texture::WRAP_S, wrap_s == trpgTextureEnv::Repeat ? Texture::REPEAT: Texture::CLAMP );
osg_texture->setWrap(Texture::WRAP_T, wrap_t == trpgTextureEnv::Repeat ? Texture::REPEAT: Texture::CLAMP );
osg_state_set->setAttributeAndModes(osg_texture, StateAttribute::ON);
if(osg_texture->getImage())
{
switch (osg_texture->getImage()->pixelFormat())
{
case GL_LUMINANCE_ALPHA:
case GL_RGBA:
osg_state_set->setMode(GL_BLEND,StateAttribute::ON);
osg_state_set->setRenderingHint(StateSet::TRANSPARENT_BIN);
}
}
int cullMode;
mat->GetCullMode(cullMode);
// Culling mode in txp means opposite from osg i.e. Front-> show front face
if( cullMode != trpgMaterial::FrontAndBack)
{
CullFace* cull_face = new CullFace;
switch (cullMode)
{
case trpgMaterial::Front:
cull_face->setMode(CullFace::BACK);
break;
case trpgMaterial::Back:
cull_face->setMode(CullFace::FRONT);
break;
}
osg_state_set->setAttributeAndModes(cull_face, StateAttribute::ON);
}
}
m_gstates.push_back(osg_state_set);
}
}
}
bool TrPageArchive::LoadModels()
{
int numModel;
modelTable.GetNumModels(numModel);
// Iterate over the models
for (int i=0; i< numModel; i++)
{
trpgModel *mod = modelTable.GetModelRef(i);
int type;
mod->GetType(type);
// Only dealing with external models currently
if (type == trpgModel::External)
{
char name[1024];
mod->GetName(name,1023);
// Load the model. It's probably not TerraPage
Node *osg_model = osgDB::readNodeFile(name);
if (!osg_model)
{
notify(WARN) << "TrPageArchive::LoadModels() error: "
<< "failed to load model: "
<< name << std::endl;
}
// Do this even if it's NULL
m_models.push_back(osg_model);
}
/*
else
{
trpgMemReadBuffer buf(GetEndian());
mod->Read(buf);
Group *osg_model = parse->ParseScene(buf, m_gstates , m_models);
m_models.push_back(osg_model);
}
*/
}
return true;
}
Group* TrPageArchive::LoadTile(int x,int y,int lod,int &parentID)
{
trpgMemReadBuffer buf(GetEndian());
// Read the tile data in, but don't parse it
if (!ReadTile(x,y,lod,buf))
return NULL;
// Call the parser
Group *tile = parse->ParseScene(buf, m_gstates , m_models);
if (tile)
{
parentID = parse->GetParentID();
// This is where you would page in textures and models
}
// That's it
return tile;
}
//----------------------------------------------------------------------------
Group* TrPageArchive::LoadAllTiles()
{
// Size information comes out of the header
const trpgHeader *head = GetHeader();
// Create one group as the top
Group *topGroup = new Group;
int32 numLod;
head->GetNumLods(numLod);
// Iterate over the LODs. Lower res LODs must be loaded
// first, otherwise there's nothing to hook the higher res
// LODs into.
trpg2iPoint tileSize;
// The group list is used to map parent IDs to pfGroup nodes
std::vector<Group *> *groupList = parse->GetGroupList();
for (int nl=0;nl<numLod;nl++)
{
// The number of tiles in X and Y changes per LOD
head->GetLodSize(nl,tileSize);
for (int x=0; x < tileSize.x; x++)
{
for (int y=0; y < tileSize.y; y++)
{
int parentID;
Group *tile = LoadTile(x,y,nl,parentID);
if (!tile)
{
notify(WARN)<< "TrPageArchive::LoadAllTiles error: "
<< "failed to load tile ("
<< x << "," << y << "," << nl << ")"
<< std::endl;
}
else
{
if (parentID == -1)
{
// Get added to the top level node
topGroup->addChild(tile);
}
else
{
// Added below some other node
(*groupList)[parentID]->addChild(tile);
}
}
}
}
}
return topGroup;
}

View File

@@ -0,0 +1,86 @@
/* **************************************************************************
* OpenSceneGraph loader for Terrapage format database
* by Boris Bralo 2002
*
* based on/modifed sgl (Scene Graph Library) loader by Bryan 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.
*
*****************************************************************************/
#ifndef _TRPAGEARCHIVE_H_
#define _TRPAGEARCHIVE_H_
#include <string>
#include <vector>
#include <memory> // for auto_ptr
#include "trpage_sys.h"
#include "trpage_read.h"
#include <osg/GeoSet>
#include "TrPageParser.h"
namespace txp
{
/// main class for loading terrapage archives
class TrPageArchive : public trpgr_Archive
{
public:
TrPageArchive();
~TrPageArchive();
// open archive file
bool OpenFile(const std::string& filename);
/// Load and create textures and materials
void LoadMaterials();
// Load and create models, usualy OpenFlight models
bool LoadModels();
/** Load a TXP tile and
@param x Tile location input - x dimension.
@param y Tile location input - y dimension.
@param lod Tile LOD level input.
@return The parent ID of this tile to let you hook it into the scene
graph.
x, y dimensions are not coordinates, they are tile numbers. For example,
for combination 10, 1 and lod number 2 terrapage opens file tile_10_1_2.tpt
in directory of the archive. This is THE method which shoud be used once
paging is implemented.
*/
osg::Group *LoadTile(int x,int y,int lod,int &parent);
/** Load all the tiles . No paging.
@return The parent of the complete scene graph.
*/
osg::Group *LoadAllTiles();
protected:
/// This class does most of the actual parsing.
std::auto_ptr<TrPageParser> parse;
// Texture, material, and model lists.
std::vector< osg::ref_ptr<osg::Texture> > m_textures;
std::vector< osg::ref_ptr<osg::StateSet> > m_gstates;
std::vector< osg::ref_ptr<osg::Node> > m_models;
std::string m_alternate_path;
};
}; // end namespace
#endif

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);
}

View File

@@ -0,0 +1,162 @@
/* **************************************************************************
* OpenSceneGraph loader for Terrapage format database
* by Boris Bralo 2002
*
* based on/modifed sgl (Scene Graph Library) loader by Bryan 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.
*
*****************************************************************************/
#ifndef _TRPAGEPARSER_H_
#define _TRPAGEPARSER_H_
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/StateSet>
#include <osg/ref_ptr>
#include <vector>
#include "trpage_read.h"
// forward declarations
namespace osg
{
class Group;
class Node;
class Material;
class Texture;
class TexEnv;
class Light;
class Transparency;
class CullFace;
};
namespace txp
{
class TrPageParser : public trpgSceneParser
{
public:
TrPageParser();
~TrPageParser();
osg::Group *ParseScene(trpgReadBuffer &,
std::vector<osg::ref_ptr<osg::StateSet> > &,
std::vector<osg::ref_ptr<osg::Node> > &);
// Return the parent of a recently parsed tile
int GetParentID() { return parentID; }
void SetParentID(int id) { parentID = id; }
// Return a reference to the tile header (after a tile has been read)
trpgTileHeader *GetTileHeaderRef();
// Return the current top node (used during parsing)
osg::Group *GetCurrTop();
// Return the current material list (passed in to ParseScene())
std::vector<osg::ref_ptr<osg::StateSet> >* GetMaterials() { return materials; }
std::vector<osg::ref_ptr<osg::Node> >* GetModels() { return models; }
// Add the Group to the group list
bool AddToGroupList(int id,osg::Group *);
// Return the group list
std::vector< osg::Group* > *GetGroupList() { return &groupList; }
// Set the maximum number of groups (once per archive)
void SetMaxGroupID(int);
protected:
bool StartChildren(void *);
bool EndChildren(void *);
protected:
osg::Group *currTop; // Current parent group
osg::Group *top; // Top group
trpgTileHeader tileHead; // Dump tile header here
// If there was an attach node, this is
// the tile's parent ID. -1 otherwise
int parentID;
std::vector<osg::ref_ptr<osg::StateSet> >* materials;
std::vector<osg::Group *> groupList;
std::vector<osg::ref_ptr<osg::Node> >* models;
};
//! callback functions for various scene graph elements
class geomRead : public trpgr_Callback {
public:
geomRead(TrPageParser *in_parse);
~geomRead();
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser *parse;
};
//----------------------------------------------------------------------------
class groupRead : public trpgr_Callback {
public:
groupRead(TrPageParser *in_parse);
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser *parse;
};
//----------------------------------------------------------------------------
class attachRead : public trpgr_Callback {
public:
attachRead(TrPageParser*in_parse);
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser*parse;
};
//----------------------------------------------------------------------------
class billboardRead : public trpgr_Callback {
public:
billboardRead(TrPageParser*in_parse);
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser*parse;
};
//----------------------------------------------------------------------------
class lodRead : public trpgr_Callback {
public:
lodRead(TrPageParser*in_parse);
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser*parse;
};
//----------------------------------------------------------------------------
class modelRefRead : public trpgr_Callback {
public:
modelRefRead(TrPageParser*in_parse);
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser*parse;
};
//----------------------------------------------------------------------------
class tileHeaderRead : public trpgr_Callback {
public:
tileHeaderRead(TrPageParser*in_parse);
void *Parse(trpgToken tok,trpgReadBuffer &buf);
protected:
TrPageParser*parse;
};
}; // namespace txp
#endif

View File

@@ -0,0 +1,27 @@
//
// TerraPage<67> loader for Open Scene Graph
//
// Copyright (C) 2002 Boris Bralo
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
// real-time rendering of large 3D photo-realistic models.
// The OSG homepage is http://www.openscenegraph.org/
//
// TerraPage is registered trademarks of Terrex.
//

117
src/osgPlugins/txp/trdll.h Normal file
View File

@@ -0,0 +1,117 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
/* trdll.h
Windows Only
This header file defines the declaration macros for DLLs.
*/
// Export/import declaration for classes and functions
// Use EXDECL class CPPDECL ... for a class
// Use CPPDECL foo *bar(bletch) for a stand-alone C++ function
// Use CDECL foo *bar(bletch) for a C function
// __COMP_DLL must be defined explicitly in Build->Settings->Code Generation
// __CURR_DLL must be defined in each header in a DLL
#ifdef TX_CLDECL
#undef TX_CLDECL
#undef TX_EXDECL
#undef TX_CDECL
#undef TX_CPPDECL
#undef TX_DODECL
#endif
// Work through cases
// If we're not compiling a DLL, or compiling the wrong DLL do import
// declarations (0), otherwise do export declarations (1)
#if !defined (__COMP_DLL)
// {secret}
#define TX_DODECL 0
#else
#if __COMP_DLL == __CURR_DLL
#define TX_DODECL 1
#else
#define TX_DODECL 0
#endif
#endif
// #if !defined (__CURR_DLL) || __COMP_DLL != __CURR_DLL
#if TX_DODECL == 0
// Modified by Paul J. Metzger (pjm@rbd.com) to support static link libraries.
// Here's the original code:
// #define TX_CLDECL __declspec( dllimport )
// #define TX_EXDECL
// #ifdef __cplusplus
// #define TX_CDECL extern "C" __declspec(dllimport)
// #else
// #define TX_CDECL extern __declspec(dllimport)
// #endif
// #define TX_CPPDECL extern __declspec(dllimport)
// Class declaration. Goes after "class" to handle DLL export in windows.
#define TX_CLDECL
// Goes before "class" to handle DLL export in windows
#define TX_EXDECL /* no-op */
// Exports a C++ function properly in a windows DLL
#define TX_CPPDECL /* no-op */
// Exports a C function properly in a windows DLL
#define TX_CDECL /* no-op */
// {secret}
#define TXDUMMY_DLL_MAIN /* no-op */
#else
#define TX_CLDECL __declspec( dllexport )
#define TX_EXDECL
#define TX_CPPDECL extern __declspec(dllexport)
#ifdef __cplusplus
#define TX_CDECL extern "C" __declspec(dllexport)
#else
#define TX_CDECL extern __declspec(dllexport)
#endif
// The following is a DLL Main function for DLLs that wouldn't otherwise
// have one. It's needed to initialize the run time library.
// This should appear once within every DLL
#ifndef TXDUMMY_DLL_MAIN
#define TXDUMMY_DLL_MAIN \
extern "C" { \
BOOL WINAPI _CRT_INIT (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved); \
BOOL APIENTRY DllMain (HANDLE hDLL, DWORD dwReason, LPVOID lpReserved) \
{ \
switch (dwReason) \
{ \
case DLL_PROCESS_ATTACH: \
{ \
if (!_CRT_INIT (hDLL, dwReason, lpReserved)) \
return FALSE; \
break; \
} \
\
case DLL_PROCESS_DETACH: \
{ \
break; \
} \
} \
return TRUE; \
} \
}
#endif
#endif
#ifndef txdll_h_
// {secret}
#define txdll_h_
#endif

View File

@@ -0,0 +1,43 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
/* trpage_basic.cpp
Methods for checkable base class.
*/
#include <stdlib.h>
#include <stdio.h>
#include "trpage_io.h"
/* Checkable
This is just a class that checks validity.
Starts out invalid.
*/
trpgCheckable::trpgCheckable()
{
valid = false;
}
trpgCheckable::~trpgCheckable()
{
valid = false;
}
bool trpgCheckable::isValid() const
{
return valid;
}

View File

@@ -0,0 +1,813 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
/* trpage_geom.cpp
Methods for the trpgGeometry class.
This includes read and write methods.
You should only need to change something in here if you want to modify
what trpgGeometry contains.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "trpage_geom.h"
#include "trpage_read.h"
#if defined(_WIN32)
#define ALIGNMENT_WORKAROUND false
#else
#define ALIGNMENT_WORKAROUND true
#endif
// Constructor
trpgGeometry::trpgGeometry()
{
primType = Polygons;
normBind = Overall;
numPrim = 0;
}
trpgGeometry::~trpgGeometry()
{
}
// Reset function
void trpgGeometry::Reset()
{
primType = Polygons;
numPrim = 0;
primLength.resize(0);
materials.resize(0);
vertDataFloat.resize(0);
vertDataDouble.resize(0);
normBind = Overall;
normDataFloat.resize(0);
normDataDouble.resize(0);
colors.resize(0);
texData.resize(0);
edgeFlags.resize(0);
}
// Set functions
void trpgGeometry::SetPrimType(PrimType type)
{
primType = type;
}
void trpgGeometry::SetPrimLengths(int num,const int *len)
{
if (num < 0)
return;
numPrim = num;
for (int i=0;i<num;i++)
primLength.push_back(len[i]);
}
void trpgGeometry::AddPrimLength(int len)
{
if (len < 0)
return;
numPrim++;
primLength.push_back(len);
}
void trpgGeometry::AddPrim()
{
numPrim++;
}
void trpgGeometry::SetNumPrims(int num)
{
numPrim = num;
}
void trpgGeometry::SetNumMaterial(int no)
{
if (no < 0)
return;
materials.resize(no,-1);
}
void trpgGeometry::SetMaterial(int which,int mat)
{
if (which < 0 || which >= (int)materials.size())
return;
materials[which] = mat;
}
void trpgGeometry::SetMaterials(int32 num,const int32 *mat)
{
materials.resize(num);
for (int i=0;i<num;i++)
materials[i] = mat[i];
}
int trpgGeometry::AddMaterial(int mat)
{
materials.push_back(mat);
return materials.size()-1;
}
// Geometry/color/normal/etc... set functions
void trpgGeometry::SetVertices(int num,const float32 *data)
{
if (num < 0)
return;
vertDataFloat.resize(0);
vertDataDouble.resize(0);
for (int i=0;i<3*num;i++)
vertDataFloat.push_back(data[i]);
}
void trpgGeometry::SetVertices(int num,const float64 *data)
{
if (num < 0)
return;
vertDataFloat.resize(0);
vertDataDouble.resize(0);
for (int i=0;i<3*num;i++)
vertDataDouble.push_back(data[i]);
}
void trpgGeometry::AddVertex(DataType type,trpg3dPoint &pt)
{
if (type == FloatData) {
vertDataFloat.push_back(pt.x);
vertDataFloat.push_back(pt.y);
vertDataFloat.push_back(pt.z);
} else {
vertDataDouble.push_back(pt.x);
vertDataDouble.push_back(pt.y);
vertDataDouble.push_back(pt.z);
}
}
void trpgGeometry::SetNormals(int num,BindType bind,const float32 *data)
{
if (num < 0)
return;
normBind = bind;
normDataFloat.resize(0);
normDataDouble.resize(0);
for (int i=0;i<3*num;i++)
normDataFloat.push_back(data[i]);
}
void trpgGeometry::SetNormals(int num,BindType bind,const float64 *data)
{
if (num <0)
return;
normBind = bind;
normDataFloat.resize(0);
normDataDouble.resize(0);
for (int i=0;i<3*num;i++)
normDataDouble.push_back(data[i]);
}
void trpgGeometry::AddNormal(DataType type,trpg3dPoint &pt)
{
if (type == FloatData) {
normDataFloat.push_back(pt.x);
normDataFloat.push_back(pt.y);
normDataFloat.push_back(pt.z);
} else {
normDataDouble.push_back(pt.x);
normDataDouble.push_back(pt.y);
normDataDouble.push_back(pt.z);
}
}
// Constructor
trpgColorInfo::trpgColorInfo()
{
}
trpgColorInfo::~trpgColorInfo()
{
}
void trpgColorInfo::Reset()
{
bind = 0;
type = 0;
data.resize(0);
}
void trpgGeometry::SetColors(int num,ColorType type,BindType bind,const trpgColor *data)
{
trpgColorInfo ci;
if (num < 0)
return;
// Set up color list
ci.type = type;
ci.bind = bind;
for (int i=0;i<num;i++)
ci.data.push_back(data[i]);
colors.push_back(ci);
}
// Constructor
trpgTexData::trpgTexData()
{
}
trpgTexData::~trpgTexData()
{
}
void trpgTexData::set(int num,int in_bind,const float32 *data)
{
bind = in_bind;
floatData.resize(0);
doubleData.resize(0);
for (int i=0;i<2*num;i++)
floatData.push_back(data[i]);
}
void trpgTexData::set(int num,int in_bind,const float64 *data)
{
bind = in_bind;
floatData.resize(0);
doubleData.resize(0);
for (int i=0;i<2*num;i++)
doubleData.push_back(data[i]);
}
void trpgTexData::Reset()
{
bind = 0;
floatData.resize(0);
doubleData.resize(0);
}
void trpgGeometry::SetTexCoords(int num,BindType bind,const float32 *data)
{
if (num < 0)
return;
trpgTexData td;
td.set(num,bind,data);
texData.push_back(td);
}
void trpgGeometry::SetTexCoords(int num,BindType bind,const float64 *data)
{
if (num < 0)
return;
trpgTexData td;
td.set(num,bind,data);
texData.push_back(td);
}
void trpgGeometry::AddTexCoord(DataType type,trpg2dPoint &pt)
{
if (texData.size() == 0)
return;
trpgTexData *td = &texData[0];
if (type == FloatData) {
td->floatData.push_back(pt.x);
td->floatData.push_back(pt.y);
} else {
td->doubleData.push_back(pt.x);
td->doubleData.push_back(pt.y);
}
}
void trpgGeometry::AddTexCoords(BindType bind)
{
trpgTexData td;
td.bind = bind;
texData.push_back(td);
}
void trpgGeometry::SetEdgeFlags(int num,const char *flags)
{
if (num < 0)
return;
edgeFlags.resize(0);
for (int i=0;i<num;i++)
edgeFlags.push_back(flags[i]);
}
// Get methods
bool trpgGeometry::GetPrimType(PrimType &t) const
{
if (!isValid()) return false;
t = (PrimType)primType;
return true;
}
bool trpgGeometry::GetNumPrims(int &n) const
{
if (!isValid()) return false;
n = numPrim;
return true;
}
bool trpgGeometry::GetPrimLengths(int *ret) const
{
if (!isValid()) return false;
for (int i=0;i<numPrim;i++)
ret[i] = primLength[i];
return true;
}
bool trpgGeometry::GetNumMaterial(int &n) const
{
if (!isValid()) return false;
n = materials.size();
return true;
}
bool trpgGeometry::GetMaterial(int id,int32 &m) const
{
if (!isValid() || id < 0 || id >= (int)materials.size()) return false;
m = materials[id];
return true;
}
bool trpgGeometry::GetNumVertex(int &v) const
{
if (!isValid()) return false;
int nvf = vertDataFloat.size();
int nvd = vertDataDouble.size();
v = MAX(nvf,nvd);
return true;
}
bool trpgGeometry::GetVertices(float32 *v) const
{
unsigned int i;
if (!isValid()) return false;
if (vertDataFloat.size() != 0)
for (i=0;i<vertDataFloat.size();i++)
v[i] = vertDataFloat[i];
else
for (i=0;i<vertDataDouble.size();i++)
v[i] = vertDataDouble[i];
return true;
}
bool trpgGeometry::GetVertices(float64 *v) const
{
unsigned int i;
if (!isValid()) return false;
if (vertDataFloat.size() != 0)
for (i=0;i<vertDataFloat.size();i++)
v[i] = vertDataFloat[i];
else
for (i=0;i<vertDataDouble.size();i++)
v[i] = vertDataDouble[i];
return true;
}
bool trpgGeometry::GetVertex(int n,trpg3dPoint &pt) const
{
int id = 3*n;
int idMax = 3*n+2;
if (id < 0 || (idMax >= (int)vertDataFloat.size() && idMax >= (int)vertDataDouble.size()))
return false;
if (vertDataFloat.size() > vertDataDouble.size()) {
pt.x = vertDataFloat[id];
pt.y = vertDataFloat[id+1];
pt.z = vertDataFloat[id+2];
} else {
pt.x = vertDataDouble[id];
pt.y = vertDataDouble[id+1];
pt.z = vertDataDouble[id+2];
}
return true;
}
bool trpgGeometry::GetNumNormal(int32 &n) const
{
if (!isValid()) return false;
if (normDataFloat.size() != 0)
n = normDataFloat.size();
if (normDataDouble.size() != 0)
n = normDataDouble.size();
return true;
}
bool trpgGeometry::GetNormals(float32 *v) const
{
unsigned int i;
if (!isValid()) return false;
if (normDataFloat.size() != 0)
for (i=0;i<normDataFloat.size();i++)
v[i] = normDataFloat[i];
else
for (i=0;i<normDataDouble.size();i++)
v[i] = normDataDouble[i];
return true;
}
bool trpgGeometry::GetNormals(float64 *v) const
{
unsigned int i;
if (!isValid()) return false;
if (normDataFloat.size() != 0)
for (i=0;i<normDataFloat.size();i++)
v[i] = normDataFloat[i];
else
for (i=0;i<normDataDouble.size();i++)
v[i] = normDataDouble[i];
return true;
}
bool trpgGeometry::GetNumColorSets(int &n) const
{
if (!isValid()) return false;
n = (int)colors.size();
return true;
}
bool trpgGeometry::GetColorSet(int id,trpgColorInfo *ci) const
{
if (!isValid() || id < 0 || id >= (int)colors.size()) return false;
*ci = colors[id];
return true;
}
bool trpgGeometry::GetNumTexCoordSets(int &n) const
{
if (!isValid()) return false;
n = (int)texData.size();
return true;
}
bool trpgGeometry::GetTexCoordSet(int id,trpgTexData *tx) const
{
if (!isValid() || id < 0 || id >= (int)texData.size()) return false;
*tx = texData[id];
return true;
}
bool trpgGeometry::GetNumEdgeFlag(int &n) const
{
if (!isValid()) return false;
n = (int)edgeFlags.size();
return true;
}
bool trpgGeometry::GetEdgeFlags(char *e) const
{
if (!isValid()) return false;
for (unsigned int i=0;i<edgeFlags.size();i++)
e[i] = edgeFlags[i];
return true;
}
// Validity check
// Note: maybe I should do this sometime
bool trpgGeometry::isValid() const
{
return true;
}
// Write geometry fields.
// Order doesn't matter very much for this
bool trpgGeometry::Write(trpgWriteBuffer &buf)
{
unsigned int i,j;
if (!isValid())
return false;
buf.Begin(TRPG_GEOMETRY);
/* Primitive info
Primitive Type
Number of primitives
Primitive array lengths
*/
buf.Begin(TRPG_GEOM_PRIM);
buf.Add(primType);
buf.Add(numPrim);
if (primLength.size() != 0) {
buf.Add((uint8)1);
for (i=0;i<(unsigned int)numPrim;i++)
buf.Add(primLength[i]);
} else
buf.Add((uint8)0);
buf.End();
/* Material info
Num materials
Material indicies
*/
if (materials.size() > 0) {
buf.Begin(TRPG_GEOM_MATERIAL);
buf.Add((int32)materials.size());
for (i=0;i<materials.size();i++)
buf.Add(materials[i]);
buf.End();
}
/* Vertices
Float and Double should never both be here
Num vertex
Vertex data
*/
if (vertDataFloat.size() > 0) {
buf.Begin(TRPG_GEOM_VERT32);
int32 num = vertDataFloat.size()/3;
buf.Add(num);
for (i=0;i<(unsigned int)3*num;i++)
buf.Add(vertDataFloat[i]);
buf.End();
}
if (vertDataDouble.size() > 0) {
buf.Begin(TRPG_GEOM_VERT64);
int32 num = vertDataDouble.size()/3;
buf.Add(num);
for (i=0;i<(unsigned int)3*num;i++)
buf.Add(vertDataDouble[i]);
buf.End();
}
/* Normals
Normal binding
Num normals
Normal data
*/
if (normDataFloat.size() > 0) {
buf.Begin(TRPG_GEOM_NORM32);
buf.Add((int32)normBind);
int32 num = normDataFloat.size()/3;
buf.Add(num);
for (i=0;i<(unsigned int)3*num;i++)
buf.Add(normDataFloat[i]);
buf.End();
}
if (normDataDouble.size() > 0) {
buf.Begin(TRPG_GEOM_NORM64);
buf.Add((int32)normBind);
int32 num = normDataDouble.size()/3;
buf.Add(num);
for (i=0;i<(unsigned int)3*num;i++)
buf.Add(normDataDouble[i]);
buf.End();
}
/* Colors
Color binding
Num colors
Colors
*/
if (colors.size() > 0) {
for (i=0;i<colors.size();i++) {
trpgColorInfo &ci = colors[i];
if (ci.data.size()) {
buf.Begin(TRPG_GEOM_COLOR);
buf.Add((int32)ci.type);
buf.Add((int32)ci.bind);
buf.Add((int32)ci.data.size());
for (j=0;j<ci.data.size();j++)
buf.Add(ci.data[j]);
buf.End();
}
}
}
/* Texture coordinates
Binding
Num coords
Texture coords
*/
for (i=0;i<texData.size();i++) {
trpgTexData &td = texData[i];
if (td.floatData.size()) {
buf.Begin(TRPG_GEOM_TEX32);
buf.Add((int32)td.bind);
int32 num = td.floatData.size()/2;
buf.Add(num);
for (j=0;j<(unsigned int)num*2;j++)
buf.Add(td.floatData[j]);
buf.End();
}
if (td.doubleData.size()) {
buf.Begin(TRPG_GEOM_TEX64);
buf.Add((int32)td.bind);
int32 num = td.doubleData.size()/2;
buf.Add(num);
for (j=0;j<(unsigned int)num*2;j++)
buf.Add(td.doubleData[j]);
buf.End();
// What is going on here? - mcmillan
//float u;
//for (j=0;j<(unsigned int)num*2;j++)
// u = (float)td.doubleData[j];
}
}
// Edge flags (for triangle strips, etc..)
if (edgeFlags.size() > 0) {
buf.Begin(TRPG_GEOM_EFLAG);
buf.Add((int32)edgeFlags.size());
for (i=0;i<edgeFlags.size();i++)
buf.Add(edgeFlags[i]);
buf.End();
}
buf.End();
return true;
}
// Geometry class is made up of individual tokens.
class geomCB : public trpgr_Callback {
public:
void *Parse(trpgToken,trpgReadBuffer &buf);
trpgGeometry *geom;
};
void *geomCB::Parse(trpgToken tok,trpgReadBuffer &buf)
{
int32 *iData;
int32 num,primType,bind,type;
float32 *fData;
float64 *dData;
trpgColor *cData;
char *charData;
uint8 hasPrimLen;
try {
switch (tok) {
case TRPG_GEOM_PRIM:
buf.Get(primType);
geom->SetPrimType((trpgGeometry::PrimType)primType);
buf.Get(num);
if (num < 0) throw 1;
geom->SetNumPrims(num);
buf.Get(hasPrimLen);
if (hasPrimLen) {
buf.GetArray(num,&iData);
if (ALIGNMENT_WORKAROUND)
{
int32 *aligned;
aligned = (int32 *)calloc (num, sizeof(int32));
memcpy (aligned, iData, num * sizeof(int32));
geom->SetPrimLengths(num, aligned);
free (aligned);
}
else
geom->SetPrimLengths(num,iData);
}
break;
case TRPG_GEOM_MATERIAL:
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(num,&iData);
if (ALIGNMENT_WORKAROUND)
{
int32 *aligned;
aligned = (int32 *)calloc (num, sizeof(int32));
memcpy (aligned, iData, num * sizeof(int32));
geom->SetMaterials(num,aligned);
free (aligned);
}
else
geom->SetMaterials(num,iData);
break;
case TRPG_GEOM_VERT32:
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(3*num,&fData);
if (ALIGNMENT_WORKAROUND)
{
float32 *aligned;
aligned = (float32 *)calloc (3*num, sizeof(float32));
memcpy (aligned, fData, 3*num * sizeof(float32));
geom->SetVertices(num,aligned);
free (aligned);
}
else
geom->SetVertices(num,fData);
break;
case TRPG_GEOM_VERT64:
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(3*num,&dData);
if (ALIGNMENT_WORKAROUND)
{
float64 *aligned;
aligned = (float64 *)calloc (3*num, sizeof(float64));
memcpy (aligned, dData, 3*num * sizeof(float64));
geom->SetVertices(num,aligned);
free (aligned);
}
else
geom->SetVertices(num,dData);
break;
case TRPG_GEOM_NORM32:
buf.Get(bind);
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(3*num,&fData);
if (ALIGNMENT_WORKAROUND)
{
float32 *aligned;
aligned = (float32 *)calloc (3*num, sizeof(float32));
memcpy (aligned, fData, 3*num * sizeof(float32));
geom->SetNormals(num,(trpgGeometry::BindType)bind,aligned);
free (aligned);
}
else
geom->SetNormals(num,(trpgGeometry::BindType)bind,fData);
break;
case TRPG_GEOM_NORM64:
buf.Get(bind);
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(3*num,&dData);
if (ALIGNMENT_WORKAROUND)
{
float64 *aligned;
aligned = (float64 *)calloc (3*num, sizeof(float64));
memcpy (aligned, dData, 3*num * sizeof(float64));
geom->SetNormals(num,(trpgGeometry::BindType)bind,aligned);
free (aligned);
}
else
geom->SetNormals(num,(trpgGeometry::BindType)bind,dData);
break;
case TRPG_GEOM_COLOR:
buf.Get(num);
if (num < 0) throw 1;
buf.Get(type);
buf.Get(bind);
buf.GetArray(num,&cData);
if (ALIGNMENT_WORKAROUND)
{
trpgColor *aligned;
aligned = (trpgColor *)calloc (num, sizeof(trpgColor));
memcpy (aligned, cData, num * sizeof(trpgColor));
geom->SetColors(num,(trpgGeometry::ColorType)type,(trpgGeometry::BindType)bind,aligned);
free (aligned);
}
else
geom->SetColors(num,(trpgGeometry::ColorType)type,(trpgGeometry::BindType)bind,cData);
break;
case TRPG_GEOM_TEX32:
buf.Get(bind);
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(2*num,&fData);
if (ALIGNMENT_WORKAROUND)
{
float32 *aligned;
aligned = (float32 *)calloc (2*num, sizeof(float32));
memcpy (aligned, fData, 2*num * sizeof(float32));
geom->SetTexCoords(num,(trpgGeometry::BindType)bind,aligned);
free (aligned);
}
else
geom->SetTexCoords(num,(trpgGeometry::BindType)bind,fData);
break;
case TRPG_GEOM_TEX64:
buf.Get(bind);
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(2*num,&dData);
if (ALIGNMENT_WORKAROUND)
{
float64 *aligned;
aligned = (float64 *)calloc (2*num, sizeof(float64));
memcpy (aligned, dData, 2*num * sizeof(float64));
geom->SetTexCoords(num,(trpgGeometry::BindType)bind,aligned);
free (aligned);
}
else
geom->SetTexCoords(num,(trpgGeometry::BindType)bind,dData);
break;
case TRPG_GEOM_EFLAG:
buf.Get(num);
if (num < 0) throw 1;
buf.GetArray(num,&charData);
geom->SetEdgeFlags(num,charData);
break;
default:
// Skip
break;
}
}
catch (...) {
return NULL;
}
return geom;
}
// Read Geometry
bool trpgGeometry::Read(trpgReadBuffer &buf)
{
trpgr_Parser parse;
geomCB gcb;
gcb.geom = this;
parse.AddCallback(TRPG_GEOM_PRIM,&gcb,false);
parse.AddCallback(TRPG_GEOM_MATERIAL,&gcb,false);
parse.AddCallback(TRPG_GEOM_VERT32,&gcb,false);
parse.AddCallback(TRPG_GEOM_VERT64,&gcb,false);
parse.AddCallback(TRPG_GEOM_NORM32,&gcb,false);
parse.AddCallback(TRPG_GEOM_NORM64,&gcb,false);
parse.AddCallback(TRPG_GEOM_COLOR,&gcb,false);
parse.AddCallback(TRPG_GEOM_TEX32,&gcb,false);
parse.AddCallback(TRPG_GEOM_TEX64,&gcb,false);
parse.AddCallback(TRPG_GEOM_EFLAG,&gcb,false);
parse.Parse(buf);
return isValid();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,315 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_header.cpp
Source for trpgHeader methods.
The only reason to change this is if you want to add something
to the header definition.
*/
#include "trpage_geom.h"
#include "trpage_read.h"
/* Write Header class
Fill it in and write it out.
*/
// Constructor
trpgHeader::trpgHeader()
{
Reset();
}
trpgHeader::~trpgHeader()
{
}
// Validity check
bool trpgHeader::isValid() const
{
if (numLods <= 0)
return false;
if (sw.x == ne.x && sw.y == ne.y)
return false;
return true;
}
// Reset contents
void trpgHeader::Reset()
{
// Initialize to a default state
verMinor = TRPG_VERSION_MINOR;
verMajor = TRPG_VERSION_MAJOR;
dbVerMinor = 0;
dbVerMajor = 0;
origin = trpg3dPoint(0,0,0);
sw = ne = trpg2dPoint(0,0);
tileType = DatabaseLocal;
numLods = 0;
lodSizes.resize(0);
lodRanges.resize(0);
tileSize.resize(0);
maxGroupID = -1;
}
// Set functions
void trpgHeader::SetVersion(int32 vmaj,int32 vmin)
{
verMinor = vmin;
verMajor = vmaj;
}
void trpgHeader::SetDbVersion(int32 vmaj,int32 vmin)
{
dbVerMinor = vmin;
dbVerMajor = vmaj;
}
void trpgHeader::SetTileSize(int id,const trpg2dPoint &pt)
{
if (id < 0 || (unsigned int)id >= tileSize.size()) return;
tileSize[id] = pt;
}
void trpgHeader::SetOrigin(const trpg3dPoint &pt)
{
origin = pt;
}
void trpgHeader::SetExtents(const trpg2dPoint &in_sw,const trpg2dPoint &in_ne)
{
sw = in_sw;
ne = in_ne;
}
void trpgHeader::SetTileOriginType(trpgTileType type)
{
tileType = type;
}
void trpgHeader::SetNumLods(int no)
{
if (no < 0) return;
numLods = no;
lodSizes.resize(no);
lodRanges.resize(no);
}
void trpgHeader::SetLodSize(int no,const trpg2iPoint &pt)
{
if (no < 0 || no >= numLods)
return;
lodSizes[no] = pt;
}
void trpgHeader::SetLodSize(const trpg2iPoint *pt)
{
for (int i=0;i<numLods;i++)
lodSizes[i] = pt[i];
}
void trpgHeader::SetLodRange(int no,float64 r)
{
if (no < 0 || no >= numLods)
return;
lodRanges[no] = r;
}
void trpgHeader::SetLodRange(const float64 *r)
{
for (int i=0;i<numLods;i++)
lodRanges[i] = r[i];
}
void trpgHeader::AddLod(const trpg2iPoint &pt,const trpg2dPoint &sz,float64 r)
{
lodRanges.push_back(r);
lodSizes.push_back(pt);
tileSize.push_back(sz);
numLods++;
}
void trpgHeader::SetMaxGroupID(int id)
{
maxGroupID = id;
}
int trpgHeader::AddGroupID(void)
{
maxGroupID++;
return maxGroupID;
}
// Write out to a buffer
bool trpgHeader::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPGHEADER);
buf.Add((int32)verMajor);
buf.Add((int32)verMinor);
buf.Add((int32)dbVerMajor);
buf.Add((int32)dbVerMinor);
buf.Add(origin);
buf.Add(sw);
buf.Add(ne);
buf.Add((uint8)tileType);
buf.Add((int32)numLods);
buf.Begin(TRPGHEAD_LODINFO);
for (int i=0;i<numLods;i++) {
buf.Add(lodSizes[i]);
buf.Add(lodRanges[i]);
buf.Add(tileSize[i]);
}
buf.End();
buf.Add(maxGroupID);
buf.End();
return true;
}
/* ********
Read Header class.
*/
// Get Functions
bool trpgHeader::GetVersion(int32 &vmaj,int32 &vmin) const
{
if (!isValid()) return false;
vmin = verMinor;
vmaj = verMajor;
return true;
}
bool trpgHeader::GetDbVersion(int32 &vmaj,int32 &vmin) const
{
if (!isValid()) return false;
vmaj = dbVerMajor;
vmin = dbVerMinor;
return true;
}
bool trpgHeader::GetTileSize(int id,trpg2dPoint &pt) const
{
if (!isValid()) return false;
if (id < 0 || (unsigned int)id >= tileSize.size()) return false;
pt = tileSize[id];
return true;
}
bool trpgHeader::GetOrigin(trpg3dPoint &pt) const
{
if (!isValid()) return false;
pt = origin;
return true;
}
bool trpgHeader::GetTileOriginType(trpgTileType &type) const
{
if (!isValid()) return false;
type = tileType;
return true;
}
bool trpgHeader::GetNumLods(int32 &no) const
{
if (!isValid()) return false;
no = numLods;
return true;
}
bool trpgHeader::GetLodSize(int32 id,trpg2iPoint &pt) const
{
if (!isValid() || (id < 0 || id >= numLods)) return false;
pt = lodSizes[id];
return true;
}
bool trpgHeader::GetLodRange(int32 id,float64 &range) const
{
if (!isValid() || (id < 0 || id >= numLods)) return false;
range = lodRanges[id];
return true;
}
bool trpgHeader::GetExtents(trpg2dPoint &osw,trpg2dPoint &one) const
{
if (!isValid()) return false;
osw = sw;
one = ne;
return true;
}
bool trpgHeader::GetMaxGroupID(int &id) const
{
id = maxGroupID;
return true;
}
// Read in the header
bool trpgHeader::Read(trpgReadBuffer &buf)
{
uint8 i8;
trpgToken tok;
bool status;
int32 len;
try {
buf.Get(verMajor);
buf.Get(verMinor);
buf.Get(dbVerMajor);
buf.Get(dbVerMinor);
buf.Get(origin);
buf.Get(sw);
buf.Get(ne);
buf.Get(i8); tileType = (trpgTileType)i8;
buf.Get(numLods);
if (numLods < 0) throw 1;
// Read in the LOD range info
buf.GetToken(tok,len);
if (tok != TRPGHEAD_LODINFO) throw 1;
buf.PushLimit(len);
status = ReadLodInfo(buf);
buf.PopLimit();
if (!status) throw 1;
// Added after the first version
buf.Get(maxGroupID);
}
catch (...) {
return false;
}
return isValid();
}
// Read the LOD info (seperate token)
bool trpgHeader::ReadLodInfo(trpgReadBuffer &buf)
{
float64 range;
trpg2iPoint pt;
trpg2dPoint sz;
try {
for (int i=0;i<numLods;i++) {
buf.Get(pt);
buf.Get(range);
buf.Get(sz);
lodSizes.push_back(pt);
lodRanges.push_back(range);
tileSize.push_back(sz);
}
}
catch (...) {
return false;
}
return true;
}

View File

@@ -0,0 +1,21 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#ifdef __CURR_DLL
#undef __CURR_DLL
#endif
// {secret}
#define __CURR_DLL 7931

View File

@@ -0,0 +1,484 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#ifndef _trpage_io_h_
#define _trpage_io_h_
/* trpage_io.h
Token definitions and basic classes.
*/
#include "trpage_sys.h"
// Macros we may need
#ifndef MIN
// {secret}
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
// {secret}
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif
// File header Magic Number
#define TRPG_MAGIC 9480372
// Current TerraPage major version
#define TRPG_VERSION_MAJOR 1
// Current TerraPage minor version
#define TRPG_VERSION_MINOR 0
// Non-existent token
// {secret}
#define TRPG_NOTOKEN 0
// 16 bit token definition value. These are values such as TRPGTEXTABLE or TRPG_ATTACH, etc...
typedef short trpgToken;
// Tokens for paging data structures
// Update the MINTOKEN and MAXTOKEN when you add tokens
// {secret}
#define TRPG_MINTOKEN 100
// {secret}
#define TRPG_PUSH 100
// {secret}
#define TRPG_POP 101
// {secret}
#define TRPGHEADER 200
// {secret}
#define TRPGHEAD_LODINFO 201
// {secret}
#define TRPGMATTABLE 300
// Added 11/14/98 - New material table
// {secret}
#define TRPGMATTABLE2 301
// Added 11/14/98
// {secret}
#define TRPGSHORTMATTABLE 302
// {secret}
#define TRPGMATERIAL 400
// {secret}
#define TRPGMAT_BASIC 401
// {secret}
#define TRPGMAT_SHADE 402
// {secret}
// {secret}
#define TRPGMAT_SIZES 403
// {secret}
#define TRPGMAT_CULL 404
// {secret}
#define TRPGMAT_ALPHA 405
// {secret}
#define TRPGMAT_NORMAL 406
// {secret}
#define TRPGMAT_TEXTURE 407
// {secret}
#define TRPGMAT_TEXENV 500
// {secret}
#define TRPGMAT_TXENV_MODE 501
// {secret}
#define TRPGMAT_TXENV_FILTER 502
// {secret}
#define TRPGMAT_TXENV_WRAP 503
// {secret}
#define TRPGMAT_TXENV_BORDER 504
// {secret}
#define TRPGTEXTABLE 600
// {secret}
#define TRPGMODELREF 700
// {secret}
#define TRPGMODELTABLE 800
// {secret}
#define TRPGTILETABLE 900
// {secret}
#define TRPG_TILE_ENTRY 901
// {secret}
#define TRPGTILEHEADER 1000
// {secret}
#define TRPG_TILE_MATLIST 1001
// {secret}
#define TRPG_TILE_MODELLIST 1002
// {secret}
#define TRPG_TILE_DATE 1003
// {secret}
#define TRPG_GROUP 2001
// {secret}
#define TRPG_BILLBOARD 2002
// {secret}
#define TRPG_LOD 2003
// {secret}
#define TRPG_TRANSFORM 2004
// {secret}
#define TRPG_MODELREF 2005
// {secret}
#define TRPG_LAYER 2006
// {secret}
#define TRPG_GEOMETRY 3000
// {secret}
#define TRPG_GEOM_PRIM 3001
// {secret}
#define TRPG_GEOM_MATERIAL 3002
// {secret}
#define TRPG_GEOM_VERT32 3003
// {secret}
#define TRPG_GEOM_VERT64 3004
// {secret}
#define TRPG_GEOM_NORM32 3005
// {secret}
#define TRPG_GEOM_NORM64 3006
// {secret}
#define TRPG_GEOM_COLOR 3007
// {secret}
#define TRPG_GEOM_TEX32 3008
// {secret}
#define TRPG_GEOM_TEX64 3009
// {secret}
#define TRPG_GEOM_EFLAG 3010
// {secret}
#define TRPG_ATTACH 4000
// {secret}
#define TRPG_MAXTOKEN 4000
// Basic data types
/* 64 bit disk reference value. */
typedef trpgllong trpgDiskRef;
// {secret}
typedef int trpgMatRef;
/* Double precision 2 dimensional point. */
TX_EXDECL class TX_CLDECL trpg2dPoint {
public:
double x, y;
trpg2dPoint (void) { };
trpg2dPoint (double in_x,double in_y) { x = in_x; y = in_y; };
};
/* Integer 2 dimensional point. This is used primarily as a 2D index value. */
TX_EXDECL class TX_CLDECL trpg2iPoint {
public:
int x,y;
trpg2iPoint (void) { };
trpg2iPoint (int in_x,int in_y) {x = in_x; y = in_y;};
};
/* Double precision 3 dimensional point. */
TX_EXDECL class TX_CLDECL trpg3dPoint {
public:
double x,y,z;
trpg3dPoint(void) { };
trpg3dPoint(double in_x,double in_y,double in_z) {x = in_x; y = in_y; z = in_z;}
};
/* Simple red, green, blue color definition */
TX_EXDECL class TX_CLDECL trpgColor {
public:
trpgColor(float64 r,float64 g,float64 b) {red = r; green = g; blue = b;}
trpgColor(void) { };
float64 red,green,blue;
};
// Used to specify machine endianess
typedef enum {LittleEndian,BigEndian} trpgEndian;
/* This is a base class for an abstract buffer type.
It contains the virtual methods for writing
data to an abstract device. The device implementation is up
to the subclass. trpgReadBuffer performs the similar function
for reading.
{group:Low Level I/O}
*/
TX_EXDECL class TX_CLDECL trpgWriteBuffer {
public:
virtual ~trpgWriteBuffer(void) { };
/* The add functions must be filled in by the child class
They add data of the appropriate type to the current buffer. */
virtual void Add(int32) = 0;
virtual void Add(int64) = 0;
virtual void Add(const char *) = 0;
virtual void Add(float32) = 0;
virtual void Add(float64) = 0;
#if (bool != int32)
virtual void Add(bool) = 0;
#endif
virtual void Add(uint8) = 0;
#if (trpgDiskRef != int64)
virtual void Add(trpgDiskRef) = 0;
#endif
// Add a token (16 bit) to the buffer
virtual void Add(trpgToken) = 0;
/* Child class method. Returns the buffer to an original state. */
virtual void Reset(void) = 0;
// See trpgMemWriteBuffer for details
virtual void Begin(trpgToken) = 0;
// See trpgMemWriteBuffer for details
virtual void End(void) = 0;
// See trpgMemWriteBuffer for details
virtual void Push(void) = 0;
// See trpgMemWriteBuffer for details
virtual void Pop(void) = 0;
// Some add functions are helpers for composite values that call the basic add functions
void Add(const trpg2iPoint &);
void Add(const trpg2dPoint &);
void Add(const trpg3dPoint &);
void Add(const trpgColor &);
/* Endianness is something the child class buffer type must set and use.
This function returns the endiannes of the current buffer. */
virtual trpgEndian GetEndian(void) { return ness; }
protected:
// Target endianness of the buffer. This should be set by the subclass on creation.
trpgEndian ness;
// Endianness of the machine we're running on.
trpgEndian cpuNess;
};
/* The Memory Write Buffer is an implementation of the Write Buffer that
uses chunks of memory. It contains implementations of the all the virtual
methods straight to memory. This is used primarily in writing archives and
tiles.
{group:Low Level I/O}
*/
TX_EXDECL class TX_CLDECL trpgMemWriteBuffer : public trpgWriteBuffer {
public:
/* The constructor takes an endianness for this buffer.
Data will automatically be converted to that as it goes in. */
trpgMemWriteBuffer(trpgEndian);
virtual ~trpgMemWriteBuffer(void);
// Return the current length of buffer
virtual int length(void) const;
// Return the raw data (if you want to write to disk, for example)
virtual const char *getData(void) const;
// Allocate the given amount of space for the buffer
virtual void setLength(unsigned int);
// Add a 32 bit integer to the buffer
virtual void Add(int32);
// Add a 64 bit integer to the buffer
virtual void Add(int64);
/* Add an arbitrary length string to the buffer.
This writes both the length and the string itself.
*/
virtual void Add(const char *);
// Add a 32 bit float to the buffer
virtual void Add(float32);
// Add a 64 bit float to the buffer
virtual void Add(float64);
#if (bool != int32)
// Add a boolean value to the buffer. It will become at least one byte.
virtual void Add(bool);
#endif
// Add an unsigned character to the buffer
virtual void Add(uint8);
#if (trpgDiskRef != int64)
// Add a 64 bit disk reference to the buffer
virtual void Add(trpgDiskRef);
#endif
// Add a token (16 bit) to the buffer
virtual void Add(trpgToken);
// Reset this buffer. This will set the current length to zero, but will not deallocate memory
virtual void Reset(void);
/* Start defining an tokenized object. The token is put into the buffer stream
and the position of a size value following it is kept. When End() is called
the buffer will rewind to that value and save the size. This method ensures
that token data can be skipped if necessary. */
virtual void Begin(trpgToken);
/* This method is called at the end of a tokenized object. See Begin for details. */
virtual void End(void);
/* Adds the TRPG_PUSH token to the current buffer. This is done by objects
that have children as they're being written. See Pop as well. */
virtual void Push(void);
/* Adds the TRPG_POP token to the current buffer. This is done by objects
that have defined children. See Push. */
virtual void Pop(void);
protected:
virtual void append(unsigned int,const char *);
virtual void set(unsigned int pos,unsigned int len,const char *);
int curLen;
int totLen;
char *data;
vector<int> lengths;
};
/* This is a virtual base class for reading data from a device.
The device implementation is left as an excercise to the sub class.
This class contains methods for getting data that must be filled in
as well as helper methods that call those.
{group:Low Level I/O}
*/
TX_EXDECL class TX_CLDECL trpgReadBuffer {
public:
virtual ~trpgReadBuffer(void) { };
/* The Get methods are utility routines that all call the GetData method.
Only that method need be filled in by a subclass. */
virtual bool Get(int32 &);
virtual bool Get(int64 &);
virtual bool Get(char *,int);
virtual bool Get(float32 &);
virtual bool Get(float64 &);
#if (bool != int32)
virtual bool Get(bool &);
#endif
virtual bool Get(uint8 &);
#if (trpgDiskRef != int64)
virtual bool Get(trpgDiskRef &);
#endif
virtual bool Get(trpgToken &);
/* These methods return references to arrays of data of the given types.
These are all utility routines and depend upon GetDataRef. */
virtual bool GetArray(int,float32 **);
virtual bool GetArray(int,float64 **);
virtual bool GetArray(int,int32 **);
virtual bool GetArray(int,trpgColor **);
virtual bool GetArray(int,char **);
virtual bool Get(trpg2iPoint &);
virtual bool Get(trpg2dPoint &);
virtual bool Get(trpg3dPoint &);
virtual bool Get(trpgColor &);
virtual bool GetToken(trpgToken &,int32 &);
/* Force the buffer to only allow the next N bytes to be read.
The limits are stack based. That is, this limit is the current one
until it's popped off the stack. Then it reverts to the previous one.
Any bytes read in the mean time count against all limits. */
virtual void PushLimit(int);
/* Revert to the limit before this one. Typically this would happen when
a tokenized object has been read. */
virtual void PopLimit(void);
/* Skip to the end of the current limit. This is done by a parser when
reading a tokenized object from the buffer to make sure that the next
object can be safely read even if the current one wasn't. */
virtual bool SkipToLimit(void);
// Buffer is empty
virtual bool isEmpty(void) = 0;
protected:
trpgEndian ness; // Endianness of the source we're reading
trpgEndian cpuNess; // Endiannees of the CPU
/* Virtual raw data retrieval function that must be implemented by a subclass.
It must return a given number of bytes in the array passed in. */
virtual bool GetData(char *,int)=0;
/* Virtual raw data reference retrieval function. The difference between
this method and GetData is that this is supposed to return a pointer
to a given amount of bytes. This assumes some sort of memory caching
mechanism in the subclass. */
virtual bool GetDataRef(char **,int)=0;
/* This virtual method must be filled in by the subclass so that SkipToLimit
will work correctly. */
virtual bool Skip(int) = 0;
/* A utility function for subclasses to use to see if they would exceed an
outside imposed limit by reading the given number of bytes. */
virtual bool TestLimit(int);
/* Utility function that must be called after a successfull read to update
the outside imposed read limits. */
virtual void UpdateLimits(int);
vector<int> limits;
};
/* This class implements a read buffer that uses a chunk of memory.
Typically, raw data will be dumped into this class, then it will be
passed to a parser for object based reading.
{group:Low Level I/O}
*/
TX_EXDECL class TX_CLDECL trpgMemReadBuffer : public trpgReadBuffer {
public:
// Memory read buffers must be initialized with an endianness
trpgMemReadBuffer(trpgEndian);
~trpgMemReadBuffer(void);
// Return true if we're out of data
bool isEmpty(void);
// Sets the size of this read buffer.
void SetLength(int);
/* Return a pointer to the raw data cache for this object. Data will
be dumped straight into here (from disk, for example) and then parsed
by something that takes a trpgReadBuffer as input. */
char *GetDataPtr(void);
protected:
bool GetData(char *,int); // Retrieve the given amount of data
bool GetDataRef(char **,int); // Retrieve a pointer to the given array
bool Skip(int); // Skip over the given amount
int len; // Data Length
int totLen; // Total allocated length
int pos; // Current position
char *data;
};
/* A Checkable is purely a base class used by other classes that
need validity checks associated with them. By default, the
checkable will return false for isValid unless the valid flag is set.
*/
TX_EXDECL class TX_CLDECL trpgCheckable {
public:
trpgCheckable(void);
virtual ~trpgCheckable(void);
// Returns the state of the valid flag, or can be overriden by a subclass to do a more complex check.
bool isValid(void) const;
protected:
/* Set this flag to true if your checkable structure doesn't have a complex
check it needs to do. */
bool valid;
};
/* The Read/Writeable is a class that knows how to read itself from a trpgReadBuffer
and write itself to a trpgWriteBuffer. This includes all the node and header
data in TerraPage. These classes are intended as marshalling points for reading
and writing data, not as data containers in and of themselves. If you find
yourself keeping a lot of classes derived from trpgReadWriteable around, you're
probably misusing them.
The classes derived from this one will have a lot of methods that begin with
"Set", "Get", and "Add". These will almost always return a bool value. This
is used to indicate whether the given call succeeded. In the case of "Set" and "Add" calls
this should always work if it possibly can. An out of range index might make it
fail, for example. "Get" calls will always fail if the object you're getting from
is not valid. Be sure to do an isValid check as soon as you've read or filled out
one of these objects.
{group:Read/Write Classes}
*/
TX_EXDECL class TX_CLDECL trpgReadWriteable : public trpgCheckable {
public:
/* The Write method is a virtual that must be filled in by the subclass.
It takes a trpgWriteBuffer and should return true on success. */
virtual bool Write(trpgWriteBuffer &) = 0;
/* The Read method should be overriden by a subclass. It should read
the contents of the given trpgReadBuffer up to the current limit
into itself. It must return true on success. */
virtual bool Read(trpgReadBuffer &) { return false;};
/* Every read/writeable must be able to reset itself to a pristine state
so that, for example, multiple objects of the same type can be read into
it, one after the other. */
virtual void Reset(void) = 0;
protected:
};
#endif

View File

@@ -0,0 +1,31 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
/* trpage_main.cpp
This file is here to provide a DLL Main.
Note: #ifdef this out on non-windows machines
*/
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include "trdll.h"
TXDUMMY_DLL_MAIN

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,325 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_mode.cpp
This source file contains the methods trpgModel and trpgModelTable.
You should only modify this code if you want to add data to these classes.
*/
#include "trpage_geom.h"
#include "trpage_read.h"
/* Write Model class
Represents a model reference.
*/
trpgModel::trpgModel()
{
name = NULL;
type = External;
useCount = 0;
}
trpgModel::trpgModel(const trpgModel &in)
{
name = NULL;
type = External;
*this = in;
}
// Reset function
void trpgModel::Reset()
{
if (name)
delete name;
name = NULL;
useCount = 0;
}
trpgModel::~trpgModel()
{
Reset();
}
// Set functions
void trpgModel::SetName(const char *nm)
{
if (name)
delete name;
name = new char[(nm ? strlen(nm) : 0)+1];
strcpy(name,nm);
type = External;
}
void trpgModel::SetReference(trpgDiskRef pos)
{
if (name)
delete name;
diskRef = pos;
type = Local;
}
void trpgModel::SetNumTiles(int num)
{
useCount = num;
}
void trpgModel::AddTile()
{
useCount++;
}
// Validity check
bool trpgModel::isValid() const
{
if (type == External && !name)
return false;
return true;
}
// Copy from one to another
trpgModel& trpgModel::operator = (const trpgModel &in)
{
if (name) {
delete name;
name = NULL;
}
type = in.type;
if (in.name)
SetName(in.name);
diskRef = in.diskRef;
useCount = in.useCount;
return *this;
}
// Compare two models
int trpgModel::operator == (const trpgModel &in) const
{
if (type != in.type)
return 0;
switch (type) {
case Local:
if (diskRef == in.diskRef)
return 1;
else
return 0;
break;
case External:
if (!name && !in.name)
return 1;
if (!name || !in.name)
return 0;
if (strcmp(name,in.name))
return 0;
break;
}
return 1;
}
// Write a model reference out
bool trpgModel::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPGMODELREF);
buf.Add(type);
if (name)
buf.Add(name);
else
buf.Add(diskRef);
buf.Add(useCount);
buf.End();
return true;
}
/* *******************
Model Read Methods
*******************
*/
// Get methods
bool trpgModel::GetType(int &t)
{
if (!isValid()) return false;
t = type;
return true;
}
bool trpgModel::GetName(char *str,int strLen) const
{
if (!isValid() || type != External) return false;
int len = (name ? strlen(name) : 0);
strncpy(str,name,MIN(len,strLen)+1);
return true;
}
bool trpgModel::GetNumTiles(int &ret) const
{
if (!isValid()) return false;
ret = useCount;
return true;
}
bool trpgModel::GetReference(trpgDiskRef &ref) const
{
if (!isValid() || type != Local) return false;
ref = diskRef;
return true;
}
bool trpgModel::Read(trpgReadBuffer &buf)
{
char tmpName[1024];
try {
buf.Get(type);
if (type == Local)
buf.Get(diskRef);
else {
buf.Get(tmpName,1023);
SetName(tmpName);
}
buf.Get(useCount);
}
catch(...) {
return false;
}
return isValid();
}
/* Write Model Reference table
Groups of models for the entire file.
*/
// Constructor
trpgModelTable::trpgModelTable()
{
}
trpgModelTable::~trpgModelTable()
{
}
// Reset function
void trpgModelTable::Reset()
{
models.resize(0);
}
// Set functions
void trpgModelTable::SetNumModels(int no)
{
models.resize(no);
}
void trpgModelTable::SetModel(int id,const trpgModel &mod)
{
if (id < 0 || (unsigned int)id >= models.size())
return;
models[id] = mod;
}
int trpgModelTable::AddModel(const trpgModel &mod)
{
models.push_back(mod);
return models.size()-1;
}
// Validity check
bool trpgModelTable::isValid() const
{
for (unsigned int i=0;i<models.size();i++)
if (!models[i].isValid())
return false;
return true;
}
// Write out the model table
bool trpgModelTable::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPGMODELTABLE);
buf.Add((int32)models.size());
for (unsigned int i=0;i<models.size();i++)
models[i].Write(buf);
buf.End();
return true;
}
/* ***************
Model Table Read methods
***************
*/
// Get methods
bool trpgModelTable::GetNumModels(int &nm) const
{
if (!isValid()) return false;
nm = models.size();
return true;
}
bool trpgModelTable::GetModel(int id,trpgModel &model) const
{
if (!isValid() || id < 0 || (unsigned int)id >= models.size())
return false;
model = models[id];
return true;
}
trpgModel *trpgModelTable::GetModelRef(int id)
{
if (id < 0 || (unsigned int)id >= models.size())
return NULL;
return &models[id];
}
bool trpgModelTable::Read(trpgReadBuffer &buf)
{
int32 numModel;
trpgModel model;
trpgToken tok;
int32 len;
bool status;
try {
buf.Get(numModel);
for (int i=0;i<numModel;i++) {
buf.GetToken(tok,len);
if (tok != TRPGMODELREF) throw 1;
buf.PushLimit(len);
status = model.Read(buf);
buf.PopLimit();
if (!status) throw 1;
models.push_back(model);
}
}
catch (...) {
return false;
}
return isValid();
}

View File

@@ -0,0 +1,640 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_nodes.cpp
The methods for all the hierarchy nodes (e.g. groups, transforms, etc...)
is here.
You should only need to modify this if you want to add something to one
of these classes.
*/
#include "trpage_geom.h"
#include "trpage_read.h"
/* Write Group
Basic group.
*/
// Constructor
trpgGroup::trpgGroup()
{
Reset();
}
trpgGroup::~trpgGroup()
{
}
// Reset
void trpgGroup::Reset()
{
numChild = 0;
id = -1;
}
// Set functions
void trpgGroup::SetNumChild(int no)
{
numChild = no;
}
int trpgGroup::AddChild()
{
numChild++;
return numChild-1;
}
void trpgGroup::SetID(int inID)
{
id = inID;
}
// Get methods
bool trpgGroup::GetNumChild(int &n) const
{
if (!isValid()) return false;
n = numChild;
return true;
}
bool trpgGroup::GetID(int &inID) const
{
if (!isValid()) return false;
inID = id;
return true;
}
// Validity check
bool trpgGroup::isValid() const
{
if (numChild <= 0) return false;
if (id < 0) return false;
return true;
}
// Write group
bool trpgGroup::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPG_GROUP);
buf.Add(numChild);
buf.Add(id);
buf.End();
return true;
}
// Read group
bool trpgGroup::Read(trpgReadBuffer &buf)
{
try {
buf.Get(numChild);
if (numChild < 0) throw 1;
buf.Get(id);
if (id < 0) throw 1;
}
catch (...) {
return false;
}
return isValid();
}
/* Write Billboard
Represents rotational billboarded geometry.
*/
// Constructor
trpgBillboard::trpgBillboard()
{
Reset();
}
trpgBillboard::~trpgBillboard()
{
}
// Reset function
void trpgBillboard::Reset()
{
id = -1;
mode = Axial;
type = Group;
axis = trpg3dPoint(0,0,1);
center = trpg3dPoint(0,0,0);
numChild = 0;
}
// Set functions
void trpgBillboard::SetCenter(const trpg3dPoint &pt)
{
center = pt;
valid = true;
}
void trpgBillboard::SetMode(int m)
{
mode = m;
}
void trpgBillboard::SetAxis(const trpg3dPoint &pt)
{
axis = pt;
}
void trpgBillboard::SetType(int t)
{
type = t;
}
// Get methods
bool trpgBillboard::GetCenter(trpg3dPoint &pt) const
{
if (!isValid()) return false;
pt = center;
return true;
}
bool trpgBillboard::GetMode(int &m) const
{
if (!isValid()) return false;
m = mode;
return true;
}
bool trpgBillboard::GetAxis(trpg3dPoint &pt) const
{
if (!isValid()) return false;
pt = axis;
return true;
}
bool trpgBillboard::GetType(int &t) const
{
if (!isValid()) return false;
t = type;
return true;
}
// Write billboard
bool trpgBillboard::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPG_BILLBOARD);
buf.Add(numChild);
buf.Add(id);
buf.Add((uint8)type);
buf.Add((uint8)mode);
buf.Add(center);
buf.Add(axis);
buf.End();
return true;
}
// Read billboard
bool trpgBillboard::Read(trpgReadBuffer &buf)
{
uint8 uChar;
try {
buf.Get(numChild);
buf.Get(id);
buf.Get(uChar); type = uChar;
buf.Get(uChar); mode = uChar;
buf.Get(center);
buf.Get(axis);
}
catch (...) {
return false;
}
return isValid();
}
/* Write Level of Detail
Represents LOD information.
*/
// Constructor
trpgLod::trpgLod()
{
Reset();
}
trpgLod::~trpgLod()
{
}
// Reset function
void trpgLod::Reset()
{
id = -1;
numRange = 0;
center = trpg3dPoint(0,0,0);
switchIn = switchOut = width = 0;
valid = true;
}
// Set functions
void trpgLod::SetCenter(const trpg3dPoint &pt)
{
center = pt;
valid = true;
}
void trpgLod::SetNumChild(int no)
{
if (no < 0)
return;
numRange = no;
}
void trpgLod::SetLOD(double in,double out,double wid)
{
switchIn = in;
switchOut = out;
width = wid;
}
void trpgLod::SetID(int inID)
{
id = inID;
}
// Get functions
bool trpgLod::GetCenter(trpg3dPoint &pt) const
{
if (!isValid()) return false;
pt = center;
return true;
}
bool trpgLod::GetNumChild(int &n) const
{
if (!isValid()) return false;
n = numRange;
return true;
}
bool trpgLod::GetLOD(double &in,double &out,double &wid) const
{
if (!isValid()) return false;
in = switchIn;
out = switchOut;
wid = width;
return true;
}
bool trpgLod::GetID(int &outID) const
{
if (!isValid()) return false;
outID = id;
return true;
}
// Write out LOD
bool trpgLod::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPG_LOD);
buf.Add(id);
buf.Add(numRange);
buf.Add(center);
buf.Add(switchIn);
buf.Add(switchOut);
buf.Add(width);
buf.End();
return true;
}
// Read in LOD
bool trpgLod::Read(trpgReadBuffer &buf)
{
try {
buf.Get(id);
buf.Get(numRange);
if (numRange < 0) throw 1;
buf.Get(center);
buf.Get(switchIn);
buf.Get(switchOut);
buf.Get(width);
}
catch (...) {
return false;
}
return isValid();
}
/* Write Layer
A layer is just a group with a different opcode.
*/
// Constructor
trpgLayer::trpgLayer()
{
}
trpgLayer::~trpgLayer()
{
}
// Write it
bool trpgLayer::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPG_LAYER);
buf.Add(numChild);
buf.Add(id);
buf.End();
return true;
}
// Read layer
bool trpgLayer::Read(trpgReadBuffer &buf)
{
try {
buf.Get(numChild);
if (numChild < 0) throw 1;
buf.Get(id);
if (id < 0) throw 1;
}
catch (...) {
return false;
}
return isValid();
}
// Reset function
void trpgLayer::Reset()
{
numChild = 0;
}
/* Write Transform
Matrix defining the transform with children.
*/
// Constructor
trpgTransform::trpgTransform()
{
Reset();
}
trpgTransform::~trpgTransform()
{
}
// Reset function
void trpgTransform::Reset()
{
id = -1;
// Note: Is this row major or column major?
m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0;
m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
}
// Set functions
void trpgTransform::SetMatrix(const float64 *im)
{
m[0][0] = im[4*0+0]; m[0][1] = im[4*0+1]; m[0][2] = im[4*0+2]; m[0][3] = im[4*0+3];
m[1][0] = im[4*1+0]; m[1][1] = im[4*1+1]; m[1][2] = im[4*1+2]; m[1][3] = im[4*1+3];
m[2][0] = im[4*2+0]; m[2][1] = im[4*2+1]; m[2][2] = im[4*2+2]; m[2][3] = im[4*2+3];
m[3][0] = im[4*3+0]; m[3][1] = im[4*3+1]; m[3][2] = im[4*3+2]; m[3][3] = im[4*3+3];
}
// Get methods
bool trpgTransform::GetMatrix(float64 *rm) const
{
if (!isValid()) return false;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
// Note: is this right?
rm[i*4+j] = m[i][j];
return true;
}
// Write transform
bool trpgTransform::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPG_TRANSFORM);
buf.Add(numChild);
buf.Add(id);
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
buf.Add(m[i][j]);
buf.End();
return true;
}
// Read transform
bool trpgTransform::Read(trpgReadBuffer &buf)
{
try {
buf.Get(numChild);
buf.Get(id);
if (numChild < 0) throw 1;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
buf.Get(m[i][j]);
}
catch (...) {
return false;
}
return isValid();
}
/* Model Reference
This is just a matrix transform and a model ID.
*/
// Constructor
trpgModelRef::trpgModelRef()
{
Reset();
}
trpgModelRef::~trpgModelRef()
{
}
// Reset function
void trpgModelRef::Reset()
{
m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0;
m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
modelRef = -1;
}
// Set functions
void trpgModelRef::SetModel(int id)
{
modelRef = id;
valid = true;
}
void trpgModelRef::SetMatrix(const float64 *im)
{
m[0][0] = im[4*0+0]; m[0][1] = im[4*0+1]; m[0][2] = im[4*0+2]; m[0][3] = im[4*0+3];
m[1][0] = im[4*1+0]; m[1][1] = im[4*1+1]; m[1][2] = im[4*1+2]; m[1][3] = im[4*1+3];
m[2][0] = im[4*2+0]; m[2][1] = im[4*2+1]; m[2][2] = im[4*2+2]; m[2][3] = im[4*2+3];
m[3][0] = im[4*3+0]; m[3][1] = im[4*3+1]; m[3][2] = im[4*3+2]; m[3][3] = im[4*3+3];
}
// Get methods
bool trpgModelRef::GetModel(int32 &mod) const
{
if (!isValid()) return false;
mod = modelRef;
return true;
}
bool trpgModelRef::GetMatrix(float64 *rm) const
{
if (!isValid()) return false;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
// Note: is this right?
rm[i*4+j] = m[i][j];
return true;
}
// Write model reference
bool trpgModelRef::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPG_MODELREF);
buf.Add(modelRef);
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
buf.Add(m[i][j]);
buf.End();
return true;
}
// Read model reference
bool trpgModelRef::Read(trpgReadBuffer &buf)
{
try {
buf.Get(modelRef);
if (modelRef < 0) throw 1;
for (int i=0;i<4;i++)
for (int j=0;j<4;j++)
buf.Get(m[i][j]);
}
catch (...) {
return false;
}
valid = true;
return isValid();
}
/* Attach Node
You'll find one of these in each tile, except for the lowest LOD.
It's basically a group with some extra info that tells you where to attach it.
The ID corresponds to the one in Group and LOD.
*/
// Constructor
trpgAttach::trpgAttach()
{
Reset();
}
trpgAttach::~trpgAttach()
{
}
// Reset
void trpgAttach::Reset()
{
parentID = -1;
childPos = -1;
}
// Parent ID is the node this one gets attached to
void trpgAttach::SetParentID(int id)
{
parentID = id;
}
bool trpgAttach::GetParentID(int &id) const
{
if (!isValid()) return false;
id = parentID;
return false;
}
// Child Position is a unique number of parent
// It could be used as an array index, for example
void trpgAttach::SetChildPos(int id)
{
childPos = id;
}
bool trpgAttach::GetChildPos(int &id) const
{
if (!isValid()) return false;
id = childPos;
return false;
}
// Validity check
bool trpgAttach::isValid() const
{
if (parentID < 0 || childPos < 0) return false;
return true;
}
// Write Attach node
bool trpgAttach::Write(trpgWriteBuffer &buf)
{
if (!isValid()) return false;
buf.Begin(TRPG_ATTACH);
buf.Add(numChild);
buf.Add(id);
buf.Add(parentID);
buf.Add(childPos);
buf.End();
return true;
}
// Read Attach node
bool trpgAttach::Read(trpgReadBuffer &buf)
{
try {
buf.Get(numChild);
buf.Get(id);
if (id < 0) throw 1;
buf.Get(parentID);
if (parentID < 0) throw 1;
buf.Get(childPos);
if (childPos < 0) throw 1;
}
catch (...) {
return false;
}
return true;
}

View File

@@ -0,0 +1,266 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
/* trpage_parse.cpp
This source file contains methods for the trpgr_Parser and trpgr_Token classes.
trpgr_Parser is the main class. It parses the basic structure of paging archive
data out of Read Buffers. You should not need to change this.
If you want to parse data out of a different structure instead, look at
subclassing trpgReadBuffer and replacing its virtual methods. That's what
trpgMemReadBuffer is doing.
This file also contains the implementation of trpgSceneParser().
That class implements a set of callbacks for handling the Pushes and Pops
in an archive. You fill in the Start/EndChildren callbacks and register
for the rest of the tokens that you want.
*/
#include "trpage_read.h"
/* ***************************
Paging token callback structure
***************************
*/
trpgr_Token::trpgr_Token()
{
cb = NULL;
destroy = true;
}
trpgr_Token::~trpgr_Token()
{
}
trpgr_Token::trpgr_Token(int in_tok,trpgr_Callback *in_cb,bool in_dest)
{
init(in_tok,in_cb,in_dest);
}
void trpgr_Token::init(int in_tok,trpgr_Callback *in_cb,bool in_dest)
{
Token = in_tok;
cb = in_cb;
destroy = in_dest;
}
// Destruct
// Destroy our callback if appropriate
void trpgr_Token::Destruct()
{
if (cb && destroy)
delete cb;
cb = NULL;
destroy = true;
}
/* ***************************
Paging parser implementation.
***************************
*/
// Constructor
trpgr_Parser::trpgr_Parser()
{
lastObject = NULL;
}
trpgr_Parser::~trpgr_Parser()
{
}
// Validity check
bool trpgr_Parser::isValid() const
{
return true;
}
// Add Callback
// Make the given callback object current for the given token.
void trpgr_Parser::AddCallback(trpgToken tok,trpgr_Callback *cb,bool in_dest)
{
RemoveCallback(tok);
tokenMap[tok] = trpgr_Token(tok,cb,in_dest);
}
// Callback used as writeable wrapper
class WriteWrapper : public trpgr_Callback {
public:
WriteWrapper(trpgReadWriteable *in_wr) { wr = in_wr; };
void *Parse(trpgToken,trpgReadBuffer &buf) {
if (wr->Read(buf))
return wr;
else
return NULL;
}
protected:
trpgReadWriteable *wr;
};
// Add Callback (writeable)
// Build a wrapper around a trpgWriteable so it can read itself
void trpgr_Parser::AddCallback(trpgToken tok,trpgReadWriteable *wr)
{
AddCallback(tok,new WriteWrapper(wr),true);
}
// Remove Callback
void trpgr_Parser::RemoveCallback(trpgToken tok)
{
tokenMap.erase(tok);
}
// Set Default Callback
// This gets called for all tokens we don't understand
void trpgr_Parser::SetDefaultCallback(trpgr_Callback *cb,bool in_dest)
{
defCb.Destruct();
defCb.init(-1,cb,in_dest);
}
/* Token Is Valid
Checks if something *could be* a token.
Doesn't necessarily mean that it is.
*/
bool trpgr_Parser::TokenIsValid(trpgToken tok)
{
if (tok < 0)
return false;
return true;
}
/* Parse Buffer
This runs through the given buffer parsing token sets until
it (1) runs out of buffer or (2) fails.
Note: Good place to return an exception, but keep it simple for now.
*/
bool trpgr_Parser::Parse(trpgReadBuffer &buf)
{
bool ret = true;
try {
while (!buf.isEmpty()) {
/* We're expecting the following
Token (int32)
Length (int32)
Data (variable)
*/
trpgToken tok;
int32 len;
if (!buf.Get(tok)) throw 1;
// Push and Pop are special - no data
if (tok != TRPG_PUSH && tok != TRPG_POP) {
if (!buf.Get(len)) throw 1;
if (!TokenIsValid(tok)) throw 1;
if (len < 0) throw 1;
// Limit what we're reading to the length of this
buf.PushLimit(len);
}
// Call our token handler for this one
try {
trpgr_Token *tcb = &tokenMap[tok];
if (!tcb)
// No such token, call the default
tcb = &defCb;
// Run the callback
if (tcb->cb) {
void *ret = tcb->cb->Parse(tok,buf);
// Note: Do something with the return value
lastObject = ret;
}
}
catch (...) {
// Don't want to screw up the limit stack
}
// No limit to worry about with push and pop
if (tok != TRPG_PUSH && tok != TRPG_POP) {
buf.SkipToLimit();
buf.PopLimit();
}
}
}
catch (...) {
// Failed to parse.
ret = false;
}
return ret;
}
/* ****************
Scene Parser
****************
*/
// Helper - callback for Push
class trpgSceneHelperPush : public trpgr_Callback {
public:
trpgSceneHelperPush(trpgSceneParser *in_parse) { parse = in_parse; };
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
// Call the start children callback
parse->StartChildren(parse->lastObject);
parse->parents.push_back(parse->lastObject);
return (void *)1;
}
protected:
trpgSceneParser *parse;
};
// Helper - callback for Pop
class trpgSceneHelperPop : public trpgr_Callback {
public:
trpgSceneHelperPop(trpgSceneParser *in_parse) { parse = in_parse; };
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
// Make sure we don't have an extra pop
if (parse->parents.size() == 0)
// Note: let someone know about the extra pop
return NULL;
// Call the end children callback
int len = parse->parents.size();
parse->EndChildren(parse->parents[len-1]);
parse->parents.resize(len-1);
return (void *)1;
}
protected:
trpgSceneParser *parse;
};
// Helper - default callback
// Puts a 1 on the parent stack
// Note: Need to use this fact above
class trpgSceneHelperDefault : public trpgr_Callback {
public:
trpgSceneHelperDefault(trpgSceneParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
// Absorb it quietly
return (void *)1;
}
protected:
trpgSceneParser *parse;
};
trpgSceneParser::trpgSceneParser()
{
// Register for Push and Pop
AddCallback(TRPG_PUSH,new trpgSceneHelperPush(this));
AddCallback(TRPG_POP,new trpgSceneHelperPop(this));
// Register for default
SetDefaultCallback(new trpgSceneHelperDefault(this));
};
trpgSceneParser::~trpgSceneParser()
{
};

View File

@@ -0,0 +1,240 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_rarchive.cpp
This source file implements the methods for a trpgr_Archive.
The Read Archive is used to read a paging archive from disk.
*/
#include "trpage_read.h"
// Constructor
trpgr_Archive::trpgr_Archive()
{
fp = NULL;
ness = LittleEndian;
strcpy(dir,".");
}
// Destructor
trpgr_Archive::~trpgr_Archive()
{
if (fp)
fclose(fp);
fp = NULL;
}
// Set the directory where the archive is
void trpgr_Archive::SetDirectory(const char *in_dir)
{
strncpy(dir,in_dir,1024);
}
// Open File
// Open the given file and look for the file specific info
bool trpgr_Archive::OpenFile(const char *name)
{
char file[1024];
sprintf(file,"%s/%s",dir,name);
CloseFile();
if (!(fp = fopen(file,"rb")))
return false;
// Look for a magic # and endianness
int32 magic;
if (fread(&magic,sizeof(int32),1,fp) != 1)
return false;
headerRead = false;
// Figure out the endianness from the magic number
trpgEndian cpuNess = trpg_cpu_byte_order();
if (magic == TRPG_MAGIC) {
ness = cpuNess;
return true;
}
if (trpg_byteswap_int(magic) == TRPG_MAGIC) {
if (cpuNess == LittleEndian)
ness = BigEndian;
else
ness = LittleEndian;
return true;
}
if (magic != TRPG_MAGIC)
return false;
// Not one of our files
return false;
}
// Close File
// Close the currently open file
void trpgr_Archive::CloseFile()
{
if (fp)
fclose(fp);
fp = NULL;
}
// Read Header
// Run through the rest of the header information
bool trpgr_Archive::ReadHeader()
{
if (!fp || headerRead)
return false;
headerRead = true;
// Eat some bytes
// char stuff[20];
// if (fread(stuff,1,20,fp) != 20) return false;
// if (fread(stuff,1,sizeof(trpgllong),fp) != sizeof(trpgllong)) return false;
// Next int64 should be the header size
trpgEndian cpuNess = trpg_cpu_byte_order();
int32 headerSize;
if (fread(&headerSize,sizeof(int32),1,fp) != 1) return false;
if (ness != cpuNess)
headerSize = trpg_byteswap_int(headerSize);
int headLen = headerSize;
if (headLen < 0) return false;
// Read in the header whole
trpgMemReadBuffer buf(ness);
buf.SetLength(headLen);
char *data = buf.GetDataPtr();
if (fread(data,1,headLen,fp) != (unsigned int)headLen) return false;
// Set up a parser
// Catch the tables we need for the archive
trpgr_Parser parser;
parser.AddCallback(TRPGHEADER,&header);
parser.AddCallback(TRPGMATTABLE,&materialTable);
parser.AddCallback(TRPGMATTABLE2,&materialTable); // Added 11-14-98
parser.AddCallback(TRPGTEXTABLE,&texTable);
parser.AddCallback(TRPGMODELTABLE,&modelTable);
parser.AddCallback(TRPGTILETABLE,&tileTable);
// Parse the buffer
if (!parser.Parse(buf))
return false;
valid = true;
return true;
}
// Read Tile
// Read a tile into a read buffer
bool trpgr_Archive::ReadTile(uint32 x,uint32 y,uint32 lod,trpgMemReadBuffer &buf)
{
if (!isValid()) return false;
// Reality check the address
int32 numLods;
header.GetNumLods(numLods);
if (/*lod < 0 ||*/ (int)lod >= numLods) return false;
trpg2iPoint lodSize;
header.GetLodSize(lod,lodSize);
if (/*x < 0 ||*/ (int)x >= lodSize.x || /*y < 0 ||*/ (int)y >= lodSize.y) return false;
// Figure out the file name
// Note: This assumes External tiles
const char *base = tileTable.GetBaseName();
char filename[1024];
sprintf(filename,"%s/%s/tile_%d_%d_%d.tpt",dir,base,x,y,lod);
// Open the file and read the contents
FILE *fp=NULL;
try {
if (!(fp = fopen(filename,"rb"))) throw 1;
// Find the file end
if (fseek(fp,0,SEEK_END)) throw 1;
// Note: This means tile is capped at 2 gigs
long pos = ftell(fp);
if (fseek(fp,0,SEEK_SET)) throw 1;
// Now we know the size. Read the whole file
buf.SetLength(pos);
char *data = buf.GetDataPtr();
if (fread(data,pos,1,fp) != 1) throw 1;
fclose(fp); fp = NULL;
}
catch (...) {
if (fp)
fclose(fp);
return false;
}
return true;
}
// Get methods
const trpgHeader *trpgr_Archive::GetHeader() const
{
return &header;
}
const trpgMatTable *trpgr_Archive::GetMaterialTable() const
{
return &materialTable;
}
const trpgTexTable *trpgr_Archive::GetTexTable() const
{
return &texTable;
}
const trpgModelTable *trpgr_Archive::GetModelTable() const
{
return &modelTable;
}
const trpgTileTable *trpgr_Archive::GetTileTable() const
{
return &tileTable;
}
trpgEndian trpgr_Archive::GetEndian() const
{
return ness;
}
// Utility MBR routine
bool trpgr_Archive::trpgGetTileMBR(uint32 x,uint32 y,uint32 lod,trpg2dPoint &ll,trpg2dPoint &ur) const
{
if (!header.isValid())
return false;
int32 numLod;
header.GetNumLods(numLod);
trpg2iPoint maxXY;
header.GetLodSize(lod,maxXY);
if (/*x < 0 ||*/ (int)x>= maxXY.x || /*y < 0 ||*/ (int)y>= maxXY.y)
return false;
trpg3dPoint origin;
header.GetOrigin(origin);
trpg2dPoint size;
header.GetTileSize(lod,size);
ll.x = origin.x + size.x*x;
ll.y = origin.y + size.y*y;
ur.x = origin.x + size.x*(x+1);
ur.y = origin.y + size.y*(y+1);
return true;
}

View File

@@ -0,0 +1,155 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#ifndef _txpage_read_h_
// {secret}
#define _txpage_read_h_
/* txpage_read.h
Classes used to represent read objects for paging files.
*/
#include "trpage_sys.h"
#include "trpage_geom.h"
/* Callback base class
Called when a given token is found.
{group:Archive Reading}
*/
TX_EXDECL class TX_CLDECL trpgr_Callback {
public:
virtual ~trpgr_Callback(void) { };
virtual void *Parse(trpgToken,trpgReadBuffer &) { return (void *)1; };
};
/* Paging Token
Stores callback info associated with a given token.
{group:Archive Reading}
*/
TX_EXDECL class TX_CLDECL trpgr_Token {
public:
trpgr_Token(void);
trpgr_Token(int,trpgr_Callback *,bool destroy=true);
~trpgr_Token(void);
void init(int,trpgr_Callback *,bool destroy=true);
int Token; // Constant token value
trpgr_Callback *cb; // Callback when we hit this token
bool destroy; // Should we call delete on the callback or not
void Destruct(void); // Not quite like delete
};
/* Parse class for paging data structures.
This executes callbacks
{group:Archive Reading}
*/
TX_EXDECL class TX_CLDECL trpgr_Parser {
public:
trpgr_Parser(void);
virtual ~trpgr_Parser(void);
bool isValid(void) const;
// Add and remove token callbacks
virtual void AddCallback(trpgToken,trpgr_Callback *,bool destroy = true);
virtual void AddCallback(trpgToken,trpgReadWriteable *);
virtual void RemoveCallback(trpgToken);
virtual void SetDefaultCallback(trpgr_Callback *,bool destroy = true);
// Parse a read buffer
virtual bool Parse(trpgReadBuffer &);
virtual bool TokenIsValid(trpgToken); // Check token validity
protected:
void *lastObject;
private:
// Note: Just how slow is a map<> anyway?
// This usage is self-contained and could be replaced with an array
#if defined(_WIN32)
typedef map<trpgToken,trpgr_Token> tok_map;
#else
typedef map<trpgToken,trpgr_Token,less<trpgToken> > tok_map;
#endif
tok_map tokenMap;
trpgr_Token defCb; // Call this when no others are called
};
/* Paging Archive (read version)
This just reads the first bits of the file (and the header)
and lets you parse from there.
{group:Archive Reading}
*/
TX_EXDECL class TX_CLDECL trpgr_Archive : public trpgCheckable {
public:
trpgr_Archive(void);
virtual ~trpgr_Archive(void);
virtual void SetDirectory(const char *);
virtual bool OpenFile(const char *); // Open File
virtual void CloseFile(void);
virtual bool ReadHeader(void); // Read header (materials, tile table. etc..)
virtual bool ReadTile(uint32 x, uint32 y, uint32 lod,trpgMemReadBuffer &);
// Get access to header info
virtual const trpgHeader *GetHeader(void) const;
virtual const trpgMatTable *GetMaterialTable(void) const;
virtual const trpgTexTable *GetTexTable(void) const;
virtual const trpgModelTable *GetModelTable(void) const;
virtual const trpgTileTable *GetTileTable(void) const;
// Utility routine to calculate the MBR of a given point
virtual bool trpgGetTileMBR(uint32 x,uint32 y,uint32 lod,
trpg2dPoint &ll,trpg2dPoint &ur) const;
trpgEndian GetEndian() const;
char* getDir(){return dir;};
protected:
bool headerRead;
trpgEndian ness;
FILE *fp;
int fid;
// Header info
char dir[1024];
trpgHeader header;
trpgMatTable materialTable;
trpgTexTable texTable;
trpgModelTable modelTable;
trpgTileTable tileTable;
};
class trpgSceneHelperPush;
class trpgSceneHelperPop;
class trpgSceneHelperDefault;
/* Scene Parser
This class assists in parsing a scene graph structure (tiles and models).
To use it, do an archive ReadTile and pass the resulting Read Buffer to this
parser.
{group:Archive Reading}
*/
TX_EXDECL class TX_CLDECL trpgSceneParser : public trpgr_Parser {
friend class trpgSceneHelperPush;
friend class trpgSceneHelperPop;
friend class trpgSceneHelperDefault;
public:
trpgSceneParser(void);
virtual ~trpgSceneParser(void);
protected:
// Start defining children for the given object
virtual bool StartChildren(void *) { return true;};
virtual bool EndChildren(void *) { return true;};
// List of objects whose children we're working on
vector<void *> parents;
};
#endif

View File

@@ -0,0 +1,430 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
/* trpage_readbuf.cpp
Methods for the trpgReadBuffer and trpgMemReadBuffer classes.
trpgReadBuffer is a virtual base class with a few utility functions.
It's used as generic interface for reading data out of.
trpgMemReadBuffer is a subclass of that which implements methods for
reading out of a chunk of memory. Data is read off of disk and then
dumped into a read buffer for parsing.
If you wanted to read directly from disk, for example, you could
implement a trpgDiskReadBuffer as a subclass of trpgReadBuffer.
*/
#include "trpage_io.h"
#include "trpage_swap.h"
/* **********************
Read buffer base class functions
**********************
*/
// Basic get functions
bool trpgReadBuffer::Get(int32 &ret)
{
int32 val;
if (!GetData((char *)&val,sizeof(int32))) return false;
if (ness != cpuNess)
ret = trpg_byteswap_int(val);
else
ret = val;
return true;
}
bool trpgReadBuffer::Get(int64 &ret)
{
int64 val;
if (!GetData((char *)&val,sizeof(int64))) return false;
if (ness != cpuNess)
ret = trpg_byteswap_llong(val);
else
ret = val;
return true;
}
bool trpgReadBuffer::Get(char *ret,int retLen)
{
int32 len;
// Get the length first
if (!Get(len)) return false;
// Read what we can
int rlen = MIN(len,retLen-1);
if (!GetData(ret,rlen)) return false;
ret[rlen] = 0;
// Skip the rest
if (!Skip(rlen-len)) return false;
return true;
}
bool trpgReadBuffer::Get(float32 &ret)
{
char cval[4];
if (!GetData(cval,sizeof(float32))) return false;
try {
if (ness == cpuNess)
memcpy(&ret,cval,4);
else
ret = trpg_byteswap_4bytes_to_float(cval);
}
catch (...) {
}
return true;
}
bool trpgReadBuffer::Get(float64 &ret)
{
char cval[8];
if (!GetData(cval,sizeof(float64))) return false;
try {
if (ness == cpuNess)
memcpy(&ret,cval,8);
else
ret = trpg_byteswap_8bytes_to_double(cval);
}
catch (...) {
}
return true;
}
bool trpgReadBuffer::Get(uint8 &ret)
{
uint8 val;
if (!GetData((char *)&val,sizeof(uint8))) return false;
// No byte swapping needed
ret = val;
return true;
}
#if (bool != int32)
bool trpgReadBuffer::Get(bool &ret)
{
uint8 val;
if (!GetData((char *)&val,sizeof(uint8))) return false;
// No byte swapping needed
ret = (val == 0) ? false : true;
return true;
}
#endif
#if (trpgDiskRef != int64)
bool trpgReadBuffer::Get(trpgDiskRef &ret)
{
trpgDiskRef val;
if (!GetData((char *)&val,sizeof(trpgDiskRef))) return false;
if (ness == cpuNess)
ret = val;
else
ret = trpg_byteswap_llong(val);
return true;
}
#endif
bool trpgReadBuffer::Get(trpgToken &ret)
{
trpgToken val;
if (!GetData((char *)&val,sizeof(trpgToken))) return false;
if (ness == cpuNess)
ret = val;
else
ret = trpg_byteswap_short(val);
return true;
}
// Array Get functions
bool trpgReadBuffer::GetArray(int len,float32 **arr)
{
if (!GetDataRef((char **)arr,sizeof(float32)*len))
return false;
// Byteswap in place if necessary
if (ness != cpuNess) {
char *ptr;
int pos;
for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=4)
trpg_swap_four(ptr,ptr);
}
return true;
}
bool trpgReadBuffer::GetArray(int len,float64 **arr)
{
if (!GetDataRef((char **)arr,sizeof(float64)*len))
return false;
// Byteswap in place if necessary
if (ness != cpuNess) {
char *ptr;
int pos;
for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=8)
trpg_swap_eight(ptr,ptr);
}
return true;
}
bool trpgReadBuffer::GetArray(int len,int32 **arr)
{
if (!GetDataRef((char **)arr,sizeof(int32)*len))
return false;
// Byteswap in place if necessary
if (ness != cpuNess) {
char *ptr;
int pos;
for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=4)
trpg_swap_four(ptr,ptr);
}
return true;
}
bool trpgReadBuffer::GetArray(int len,trpgColor **arr)
{
if (!GetDataRef((char **)arr,sizeof(trpgColor)*len))
return false;
// Byteswap in place if necessary
if (ness != cpuNess) {
char *ptr;
int pos;
for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=8)
trpg_swap_four(ptr,ptr);
}
return true;
}
bool trpgReadBuffer::GetArray(int len,char **arr)
{
return GetDataRef((char **)arr,sizeof(char)*len);
}
// Utility Get functions - Just call the others
bool trpgReadBuffer::Get(trpg2iPoint &pt)
{
if (!Get(pt.x) || !Get(pt.y))
return false;
return true;
}
bool trpgReadBuffer::Get(trpg2dPoint &pt)
{
if (!Get(pt.x) || !Get(pt.y))
return false;
return true;
}
bool trpgReadBuffer::Get(trpg3dPoint &pt)
{
if (!Get(pt.x) || !Get(pt.y) || !Get(pt.z))
return false;
return true;
}
bool trpgReadBuffer::Get(trpgColor &color)
{
if (!Get(color.red) || !Get(color.green) || !Get(color.blue))
return false;
return true;
}
// Get both a token and it's length, since that's fairly common
bool trpgReadBuffer::GetToken(trpgToken &tok,int32 &len)
{
if (!Get(tok) || !Get(len))
return false;
return true;
}
/* Limit Handling functions
These impose arbitrary lenght limits on the read buffer.
This keeps us from reading pased a token group and parsing
random data within an archive.
*/
// Push Limit
// Add another limit to the top of the stack
void trpgReadBuffer::PushLimit(int limit)
{
limits.push_back(limit);
}
// Pop Limit
// Remove the current limit from the stack
void trpgReadBuffer::PopLimit()
{
int len = limits.size();
if (len > 0)
limits.resize(len-1);
}
// Skip To Limit
// Skip to the end of the current limit.
// This happens when we bag the rest of the current token
bool trpgReadBuffer::SkipToLimit()
{
int len=0;
if (limits.size() != 0)
len = limits[limits.size()-1];
if (len > 0)
return Skip(len);
return true;
}
// Test Limit
// See if the next read is going to blow the limits
bool trpgReadBuffer::TestLimit(int len)
{
for (unsigned int i=0;i<limits.size();i++)
if (len > limits[i])
return false;
return true;
}
// Update Limits
// We just read a few bytes. Update the limits
void trpgReadBuffer::UpdateLimits(int len)
{
for (unsigned int i=0;i<limits.size();i++)
limits[i] -= len;
}
/* *************************
Memory Read Buffer
*************************
*/
trpgMemReadBuffer::trpgMemReadBuffer(trpgEndian in_ness)
{
data = NULL;
len = totLen = pos = 0;
ness = in_ness;
cpuNess = trpg_cpu_byte_order();
}
trpgMemReadBuffer::~trpgMemReadBuffer()
{
if (data)
delete data;
}
// Empty check
bool trpgMemReadBuffer::isEmpty()
{
if (!data) return true;
if (pos >= len)
return true;
// Also test the limits
for (unsigned int i=0;i<limits.size();i++)
if (limits[i] == 0) return true;
return false;
}
// Set Length
// Allocate the given space
void trpgMemReadBuffer::SetLength(int newLen)
{
if (newLen > totLen) {
if (data)
delete data;
data = new char[newLen];
totLen = newLen;
}
len = newLen;
pos = 0;
}
// Get Data Ptr
// Return a pointer to our data so it can be written to
char *trpgMemReadBuffer::GetDataPtr()
{
return data;
}
// Get Data
// Protected method for actually retrieving a piece of data
bool trpgMemReadBuffer::GetData(char *ret,int rlen)
{
if (rlen < 0)
return false;
// Test against limits imposed from without
if (!TestLimit(rlen)) throw 1;
// See if we've actually got the data
if (pos+rlen > len) throw 1;
// Copy into the return buffer
memcpy(ret,&data[pos],rlen);
// Update any limits we might have
UpdateLimits(rlen);
pos += rlen;
return true;
}
// Get Reference to Data
// Protected method that retrieves a reference to the given amoutn of data
bool trpgMemReadBuffer::GetDataRef(char **ret,int rlen)
{
if (rlen < 0) return false;
// Test against limits
if (!TestLimit(rlen)) throw 1;
if (pos + rlen > len) throw 1;
// Set up reference
*ret = &data[pos];
UpdateLimits(rlen);
pos += rlen;
return true;
}
// Skip
// Same as read except we're not, uh, reading
bool trpgMemReadBuffer::Skip(int rlen)
{
if (rlen < 0)
return false;
// Test against limits
if (!TestLimit(rlen)) return false;
if (pos + rlen > len) return false;
UpdateLimits(rlen);
pos += rlen;
return true;
}

View File

@@ -0,0 +1,555 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_scene.cpp
This file implements a bunch of stuff, all of it optional. See trpage_scene.h
for more information.
Scene Graph nodes -
All the methods for the simple scene graph are here.
trpgSceneGraphParser -
This is a subclass of trpgSceneParser. It uses that utility class to keep track
of pushes and pops. It also registers an interest in all the node types it
knows about (Geometry,Group,LOD,ModelRef). When one of those is encountered
by the trpgr_Parser (which it's also a subclass of) it reads it into the
appropriate trpgRead* type.
Unless you're reading into the scene graph defined in trpage_scene.h, you won't
use this class directly. Instead, copy it and use it as a template for how
to read into a scene graph. You'll need to replace the helpers, primarily.
*/
#include <trpage_read.h>
#include <trpage_scene.h>
/* ****************
MBR Calculation and handling
****************
*/
trpgMBR::trpgMBR()
{
valid = false;
}
bool trpgMBR::isValid() const
{
return valid;
}
void trpgMBR::Reset()
{
valid = false;
}
trpg3dPoint trpgMBR::GetLL() const
{
return ll;
}
trpg3dPoint trpgMBR::GetUR() const
{
return ur;
}
void trpgMBR::AddPoint(const trpg3dPoint &pt)
{
if (valid) {
ll.x = MIN(pt.x,ll.x);
ll.y = MIN(pt.y,ll.y);
ll.z = MIN(pt.z,ll.z);
ur.x = MAX(pt.x,ur.x);
ur.y = MAX(pt.y,ur.y);
ur.z = MAX(pt.z,ur.z);
} else {
valid = true;
ll = ur = pt;
}
}
void trpgMBR::AddPoint(double x,double y,double z)
{
AddPoint(trpg3dPoint(x,y,z));
}
void trpgMBR::GetMBR(trpg3dPoint &oll,trpg3dPoint &our) const
{
oll = ll;
our = ur;
}
// Add the input MBR to this one
void trpgMBR::Union(const trpgMBR &in)
{
if (valid) {
if (in.isValid()) {
AddPoint(in.GetLL());
AddPoint(in.GetUR());
}
} else {
valid = true;
*this = in;
}
}
// See if there's any overlap between the two MBRs
bool trpgMBR::Overlap(const trpg2dPoint &ill, const trpg2dPoint &iur) const
{
if (!isValid()) return false;
trpg2dPoint ilr = trpg2dPoint(iur.x,ill.y);
trpg2dPoint iul = trpg2dPoint(ill.x,iur.y);
// B MBR falls within A
if (Within(ill) || Within(iur) || Within(ilr) || Within(iul))
return true;
// A MBR falls within B
if ((inRange(ill.x,iur.x,ll.x) && inRange(ill.y,iur.y,ll.y)) ||
(inRange(ill.x,iur.x,ur.x) && inRange(ill.y,iur.y,ll.y)) ||
(inRange(ill.x,iur.x,ur.x) && inRange(ill.y,iur.y,ur.y)) ||
(inRange(ill.x,iur.x,ll.x) && inRange(ill.y,iur.y,ur.y)))
return true;
if ((inRange(ll.x,ur.x,ill.x) && ill.y < ll.y && iur.y > ur.y) ||
(inRange(ll.y,ur.y,ill.y) && ill.x < ll.x && iur.x > ur.x))
return true;
return false;
}
// Check if a given 2d point is within the MBR
bool trpgMBR::Within(const trpg2dPoint &pt) const
{
if (inRange(ll.x,ur.x,pt.x) && inRange(ll.y,ur.y,pt.y))
return true;
return false;
}
/* ****************
Read Group Base
Base class for all group structures.
****************
*/
// Destructor
trpgReadGroupBase::~trpgReadGroupBase()
{
DeleteChildren();
}
// Delete all children
void trpgReadGroupBase::DeleteChildren()
{
for (unsigned int i=0;i<children.size();i++)
if (children[i])
delete children[i];
}
// Add a child to the list
void trpgReadGroupBase::AddChild(trpgReadNode *n)
{
children.push_back(n);
}
// Unref a child (but don't delete it)
void trpgReadGroupBase::unRefChild(int id)
{
if (id < 0 || id >= (int)children.size())
return;
children[id] = NULL;
}
// Unref all the children (they've probably been moved elsewhere)
void trpgReadGroupBase::unRefChildren()
{
for (unsigned int i=0;i<children.size();i++)
unRefChild(i);
}
// Calculate an MBR
trpgMBR trpgReadGroupBase::GetMBR() const
{
if (mbr.isValid())
return mbr;
else {
// Calculate and cache a new MBR
trpgMBR *cmbr = const_cast<trpgMBR *>(&mbr);
trpgMBR kmbr;
// Ask the kids
for (unsigned int i=0;i<children.size();i++) {
kmbr = children[i]->GetMBR();
cmbr->Union(kmbr);
}
return *cmbr;
}
}
/* ****************
Read Geometry
****************
*/
// Calculate an MBR
trpgMBR trpgReadGeometry::GetMBR() const
{
if (mbr.isValid())
return mbr;
trpgMBR *pmbr = const_cast<trpgMBR *>(&mbr);
int numVert,i;
trpg3dPoint pt;
data.GetNumVertex(numVert);
numVert /= 3;
for (i=0;i<numVert;i++) {
data.GetVertex(i,pt);
pmbr->AddPoint(pt);
}
return mbr;
}
/* ****************
Scene Graph Parser
****************
*/
/* Scene Graph Parser Helpers
Each of these classes reads a certain kind of data (e.g. a group)
and creates the appropriate trpgrRead* form and returns that.
*/
/* This is a helper registered by trpgSceneGraphParser that readers trpgGeometry
nodes and adds them to the current scene graph. trpgGeometry nodes are
always leaves so there should be no pushes after this node. The Parse method
also adds the new node as a child to any existing (e.g. top) group.
{group:Demonstration Scene Graph}
*/
class trpgReadGeometryHelper : public trpgr_Callback {
public:
trpgReadGeometryHelper(trpgSceneGraphParser *in_parse) { parse = in_parse;}
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadGeometry *geom = new trpgReadGeometry();
trpgGeometry *data = geom->GetData();
if (!data->Read(buf)) {
delete geom;
return NULL;
}
trpgReadGroupBase *top = parse->GetCurrTop();
if (top)
top->AddChild(geom);
else
delete geom;
return geom;
}
protected:
trpgSceneGraphParser *parse;
};
/* This helper is registered by trpgSceneGraphParser. It reads a trpgGroup
from the trpgReadBuffer. It then adds it to our current scene graph.
It also adds an index corresponding to the group's group ID in our group
mapping in trpgSceneGraphParser. The new group becomes the top one
after returning from the Parse call.
{group:Demonstration Scene Graph}
*/
class trpgReadGroupHelper : public trpgr_Callback {
public:
trpgReadGroupHelper(trpgSceneGraphParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadGroup *group = new trpgReadGroup();
trpgGroup *data = group->GetData();
if (!data->Read(buf)) {
delete group;
return NULL;
}
trpgReadGroupBase *top = parse->GetCurrTop();
if (top)
top->AddChild(group);
else
delete group;
// Add to the group map
int id;
data->GetID(id);
trpgSceneGraphParser::GroupMap *gmap = parse->GetGroupMap();
(*gmap)[id] = group;
return group;
}
protected:
trpgSceneGraphParser *parse;
};
class trpgReadBillboardHelper : public trpgr_Callback {
public:
trpgReadBillboardHelper(trpgSceneGraphParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadBillboard *group = new trpgReadBillboard();
trpgBillboard *data = group->GetData();
if (!data->Read(buf)) {
delete group;
return NULL;
}
trpgReadGroupBase *top = parse->GetCurrTop();
if (top)
top->AddChild(group);
else
delete group;
// Add to the group map
int id;
data->GetID(id);
trpgSceneGraphParser::GroupMap *gmap = parse->GetGroupMap();
(*gmap)[id] = group;
return group;
}
protected:
trpgSceneGraphParser *parse;
};
class trpgReadAttachHelper : public trpgr_Callback {
public:
trpgReadAttachHelper(trpgSceneGraphParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadAttach *attach = new trpgReadAttach();
trpgAttach *data = attach->GetData();
if (!data->Read(buf)) {
delete attach;
return NULL;
}
trpgReadGroupBase *top = parse->GetCurrTop();
if (top)
top->AddChild(attach);
else
delete attach;
// Add to the group map
int id;
data->GetID(id);
trpgSceneGraphParser::GroupMap *gmap = parse->GetGroupMap();
(*gmap)[id] = attach;
return attach;
}
protected:
trpgSceneGraphParser *parse;
};
class trpgReadLodHelper : public trpgr_Callback {
public:
trpgReadLodHelper(trpgSceneGraphParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadLod *lod = new trpgReadLod();
trpgLod *data = lod->GetData();
if (!data->Read(buf)) {
delete lod;
return NULL;
}
trpgReadGroupBase *top = parse->GetCurrTop();
if (top)
top->AddChild(lod);
else
delete lod;
// Add to the group map
int id;
data->GetID(id);
trpgSceneGraphParser::GroupMap *gmap = parse->GetGroupMap();
(*gmap)[id] = lod;
return lod;
}
protected:
trpgSceneGraphParser *parse;
};
class trpgReadModelRefHelper : public trpgr_Callback {
public:
trpgReadModelRefHelper(trpgSceneGraphParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadModelRef *mod = new trpgReadModelRef();
trpgModelRef *data = mod->GetData();
if (!data->Read(buf)) {
delete mod;
return NULL;
}
trpgReadGroupBase *top = parse->GetCurrTop();
if (top)
top->AddChild(mod);
else
delete mod;
return mod;
}
protected:
trpgSceneGraphParser *parse;
};
class trpgReadTileHeaderHelper : public trpgr_Callback {
public:
trpgReadTileHeaderHelper(trpgSceneGraphParser *in_parse) { parse = in_parse; }
void *Parse(trpgToken tok,trpgReadBuffer &buf) {
trpgReadTileHeader *th = parse->GetTileHeaderRef();
trpgTileHeader *data = th->GetData();
if (!data->Read(buf))
return NULL;
return th;
}
protected:
trpgSceneGraphParser *parse;
};
/* The Scene Graph Parser constructor does two things. First, it sets
up any internal variables like a normal constructor. Then it registers
an interest in all the node types it knows how to parse. It does this
by calling AddCallback, which is a method of its parent. It passes in
a token representing the node type (see trpg_io.h) and an object that
is capable of parsing the given type.
The objects we pass in here are called helpers. They parse specific
objects and add them to the user defined scene graph. Examples include
trpgReadGeometryHelper, trpgReadGroupHelper, trpgReadAttachHelper,
trpgReadBillboardHelper, trpgReadLodHelper, trpgReadModelRefHelper,
trpgReadTileHeaderHelper. These are all derived from trpgr_Callback.
You should not use any of these yourself. Instead look at these classes
as examples of how to implement your own subclass of trpgSceneParser.
*/
trpgSceneGraphParser::trpgSceneGraphParser()
{
top = currTop = NULL;
// Register the readers
AddCallback(TRPG_GEOMETRY,new trpgReadGeometryHelper(this));
AddCallback(TRPG_GROUP,new trpgReadGroupHelper(this));
AddCallback(TRPG_ATTACH,new trpgReadAttachHelper(this));
AddCallback(TRPG_BILLBOARD,new trpgReadBillboardHelper(this));
AddCallback(TRPG_LOD,new trpgReadLodHelper(this));
// AddCallback(TRPG_TRANSFORM,new trpgReadTransformHelper(this));
AddCallback(TRPG_MODELREF,new trpgReadModelRefHelper(this));
// AddCallback(TRPG_LAYER,new trpgReadLayerHelper(this));
AddCallback(TRPGTILEHEADER,new trpgReadTileHeaderHelper(this));
}
// Get Current Top node
trpgReadGroupBase *trpgSceneGraphParser::GetCurrTop()
{
if (!currTop)
return NULL;
if (currTop->isGroupType())
return (trpgReadGroupBase *)currTop;
return NULL;
}
// Return a pointer to the tile header record
trpgReadTileHeader *trpgSceneGraphParser::GetTileHeaderRef()
{
return &tileHead;
}
// Parse Scene
// Parse a buffer and return the resulting scene graph
trpgReadNode *trpgSceneGraphParser::ParseScene(trpgReadBuffer &buf,GroupMap &inGmap)
{
gmap = &inGmap;
trpgTileHeader *data = tileHead.GetData();
data->Reset();
// Always put a group up top, since there might be more than
// one node at the top level in the file.
top = currTop = new trpgReadGroup();
// All the setup for tokens is handled in the constructor
// Just call parse
if (!Parse(buf)) {
// Failed to parse correctly. Give up.
delete top;
return NULL;
}
return top;
}
// 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 trpgSceneGraphParser::StartChildren(void *in_node)
{
trpgReadNode *node = (trpgReadNode *)in_node;
if (!node || !node->isGroupType()) {
// Looks like there's a push in the wrong place
// Make the current "top" NULL.
// This will drop all node until we pop back above
currTop = NULL;
} else {
// This node is our new "top"
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 trpgSceneGraphParser::EndChildren(void * /*in_node*/)
{
// We don't need it here, but this is the node we just
// finished putting children under. If you need to close
// it out in some way, do that here
//trpgReadNode *node = (trpgReadNode *)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 = (trpgReadNode *)parents[pos];
return true;
}
// Return group map (for use by helpers)
trpgSceneGraphParser::GroupMap *trpgSceneGraphParser::GetGroupMap()
{
return gmap;
}
/* ***********
Test functions
***********
*/
// Test all the tiles in an archive
bool trpgTestArchive(trpgr_Archive &archive)
{
int numLod;
trpg2iPoint tileSize;
trpgSceneGraphParser parse;
trpgReadNode *scene;
trpgSceneGraphParser::GroupMap gmap;
if (!archive.isValid()) return false;
const trpgHeader *head = archive.GetHeader();
head->GetNumLods(numLod);
// Iterate over the lods
int nl,x,y;
trpgMemReadBuffer buf(archive.GetEndian());
trpg2dPoint ll,ur;
for (nl = 0;nl < numLod;nl++) {
head->GetLodSize(nl,tileSize);
// Iterate over the tiles within those
for (x = 0; x < tileSize.x; x++)
for (y = 0; y < tileSize.y; y++) {
archive.trpgGetTileMBR(x,y,nl,ll,ur);
if (archive.ReadTile(x,y,nl,buf)) {
// Parse it
scene = parse.ParseScene(buf,gmap);
if (scene)
delete scene;
}
}
}
return true;
}

View File

@@ -0,0 +1,239 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#ifndef _txpage_scene_h_
// {secret}
#define _txpage_scene_h_
/* trpage_scene.h
Scene Graph definition.
This is a small scene graph we use for testing.
It's not intended to replace the scene graph you may already be using.
You do not need to translate from this scene graph structure to your own,
at run-time. Instead, use this file and trpage_scene.cpp as a guideline
for how to read TerraPage format into your own scene graph.
*/
#include "trpage_geom.h"
/*
{group:Demonstration Scene Graph}
*/
TX_EXDECL class TX_CLDECL trpgMBR {
public:
trpgMBR(void);
~trpgMBR(void) { };
bool isValid() const;
void Reset();
void AddPoint(const trpg3dPoint &);
void AddPoint(double,double,double);
void GetMBR(trpg3dPoint &ll,trpg3dPoint &ur) const;
trpg3dPoint GetLL() const;
trpg3dPoint GetUR() const;
void Union(const trpgMBR &);
// bool Overlap(const trpgMBR &) const;
bool Overlap(const trpg2dPoint &ll, const trpg2dPoint &ur) const;
// bool Within(const trpg3dPoint &) const
bool Within(const trpg2dPoint &) const;
protected:
inline bool inRange(double minv,double maxv,double val) const { return (val >= minv && val <= maxv); }
bool valid;
trpg3dPoint ll,ur;
};
// Read Node
// Simple Scenegraph node used for read testing
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadNode {
public:
virtual ~trpgReadNode() { };
virtual bool isGroupType() = 0;
virtual int GetType() { return type; }
virtual trpgMBR GetMBR() const { return trpgMBR(); }
protected:
int type;
};
// Read Group Base
// Base class for all group nodes
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadGroupBase : public trpgReadNode {
public:
virtual ~trpgReadGroupBase();
void AddChild(trpgReadNode *);
bool isGroupType() { return true; }
int GetNumChildren() { return children.size(); }
trpgReadNode *GetChild(int i) { return children[i]; }
trpgMBR GetMBR() const;
void unRefChild(int i);
void unRefChildren();
protected:
trpgMBR mbr;
void DeleteChildren();
vector<trpgReadNode *> children;
};
// Read Geometry
// The leaf for this scene graph
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadGeometry : public trpgReadNode {
public:
trpgReadGeometry() { type = TRPG_GEOMETRY; }
~trpgReadGeometry() { };
bool isGroupType() { return false; }
trpgGeometry *GetData() { return &data; }
trpgMBR GetMBR() const;
protected:
trpgMBR mbr;
trpgGeometry data;
};
// Read Tile Header
// One per tile. Info about what materials and models are used
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadTileHeader : public trpgReadNode {
public:
trpgReadTileHeader() { type = TRPGTILEHEADER; }
~trpgReadTileHeader() { };
bool isGroupType() { return false; }
trpgTileHeader *GetData() { return &data; }
trpgMBR GetMBR() const { trpgMBR mbr; return mbr; };
protected:
trpgTileHeader data;
};
// Read Group
// Simple group structure
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadGroup : public trpgReadGroupBase {
public:
trpgReadGroup() { type = TRPG_GROUP; }
~trpgReadGroup() { };
trpgGroup *GetData() { return &data; }
protected:
trpgGroup data;
};
// Read Attach
// Should be the top of a higher LOD tile
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadAttach : public trpgReadGroupBase {
public:
trpgReadAttach() { type = TRPG_ATTACH; }
~trpgReadAttach() { };
trpgAttach *GetData() { return &data; }
protected:
trpgAttach data;
};
// Read billboard
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadBillboard : public trpgReadGroupBase {
public:
trpgReadBillboard() { type = TRPG_BILLBOARD; }
~trpgReadBillboard() { };
trpgBillboard *GetData() { return &data; }
protected:
trpgBillboard data;
};
// Read LOD
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadLod : public trpgReadGroupBase {
public:
trpgReadLod() { type = TRPG_LOD; }
~trpgReadLod() { };
trpgLod *GetData() { return &data; }
protected:
trpgLod data;
};
// Read Layer
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadLayer : public trpgReadGroupBase {
public:
trpgReadLayer() { type = TRPG_LAYER; }
~trpgReadLayer() { };
trpgLayer *GetData() { return &data; }
protected:
trpgLayer data;
};
// Read Transform
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadTransform : public trpgReadGroupBase {
public:
trpgReadTransform() { type = TRPG_TRANSFORM; }
~trpgReadTransform() { };
trpgTransform *GetData() { return &data; }
protected:
trpgTransform data;
};
// Read Model Reference
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgReadModelRef : public trpgReadGroupBase {
public:
trpgReadModelRef() { type = TRPG_MODELREF; }
~trpgReadModelRef() { };
trpgModelRef *GetData() { return &data; }
protected:
trpgModelRef data;
};
/* Scene Graph Parser
Parses a read buffer and returns a full scenegraph.
You don't want to use this if you're reading into your own scenegraph.
Instead, you'll want to sublcass trpgSceneParser, which is a helper
class to keep track of pushes and pops and implement the same functionality
that trpgSceneGraphParser has for your own scene graph.
*/
// {group:Demonstration Scene Graph}
TX_EXDECL class TX_CLDECL trpgSceneGraphParser : public trpgSceneParser {
public:
#if defined(_WIN32)
typedef map<int,trpgReadGroupBase *> GroupMap;
#else
typedef map<int,trpgReadGroupBase *,less<int> > GroupMap;
#endif
trpgSceneGraphParser();
~trpgSceneGraphParser() { };
// Call this instead of Parse()
// Deleting it is your responsibility
trpgReadNode *ParseScene(trpgReadBuffer &,GroupMap &);
trpgReadGroupBase *GetCurrTop(); // Get the current parent object
trpgReadTileHeader *GetTileHeaderRef();
// For use by the helpers only
GroupMap *GetGroupMap();
protected:
bool StartChildren(void *);
bool EndChildren(void *);
trpgReadNode *currTop; // Current parent group
trpgReadNode *top; // Top of everything
GroupMap *gmap;
trpgReadTileHeader tileHead; // Tile header gets read into here
};
/* Test Archive
Utility function that loads and tests all tiles.
The only reason you'd want to call this is to test a TerraPage archive
you'd written.
*/
// {group:Demonstration Scene Graph}
TX_CPPDECL bool trpgTestArchive(trpgr_Archive &);
#endif

View File

@@ -0,0 +1,210 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
/* trpage_swap.h
Byte swapping utility functions.
*/
#include "trpage_swap.h"
/*
** func: swap_two( in, out )
**
** desc: byte-swaps a two-byte array.
*/
void trpg_swap_two ( const char *in, char *out )
{
char tmp[2];
tmp[0] = in[1] ;
tmp[1] = in[0] ;
memcpy(out,tmp,2);
}
/*
** func: swap_four( in, out )
**
** desc: byte-swaps a four-byte array.
*/
void trpg_swap_four ( const char *in, char *out )
{
char tmp[4];
tmp[0] = in[3] ;
tmp[1] = in[2] ;
tmp[2] = in[1] ;
tmp[3] = in[0] ;
memcpy(out,tmp,4);
}
/*
** func: swap_eight( in, out )
**
** desc: byte-swaps an eight-byte array.
*/
void trpg_swap_eight ( const char *in, char *out )
{
char tmp[8];
tmp[0] = in[7] ;
tmp[1] = in[6] ;
tmp[2] = in[5] ;
tmp[3] = in[4] ;
tmp[4] = in[3] ;
tmp[5] = in[2] ;
tmp[6] = in[1] ;
tmp[7] = in[0] ;
memcpy(out,tmp,8);
}
/*
** func: swap_sixteen( in, out )
**
** desc: byte-swaps an sixteen-byte array.
*/
void trpg_swap_sixteen ( const char *in, char *out )
{
char tmp[16];
tmp[0] = in[15] ;
tmp[1] = in[14] ;
tmp[2] = in[13] ;
tmp[3] = in[12] ;
tmp[4] = in[11] ;
tmp[5] = in[10] ;
tmp[6] = in[9] ;
tmp[7] = in[8] ;
tmp[8] = in[7] ;
tmp[9] = in[6] ;
tmp[10] = in[5] ;
tmp[11] = in[4] ;
tmp[12] = in[3] ;
tmp[13] = in[2] ;
tmp[14] = in[1] ;
tmp[15] = in[0] ;
memcpy(out,tmp,16);
}
/*
** func: tx_byteswap_short( number )
**
** desc: byte-swaps a short int.
*/
short trpg_byteswap_short( short number )
{
short result;
trpg_swap_two( (const char*) &number, (char*) &result );
return result;
}
/*
** func: tx_byteswap_int( number )
**
** desc: byte-swaps an int.
*/
int trpg_byteswap_int( int number )
{
int result;
trpg_swap_four( (const char*) &number, (char*) &result );
return result;
}
/*
** func: tx_byteswap_long( number )
**
** desc: byte-swaps a long int.
*/
long trpg_byteswap_long( long number )
{
long result;
trpg_swap_four( (const char*) &number, (char*) &result );
return result;
}
/*
** func: tx_byteswap_float( number )
**
** desc: byte-swaps a float.
*/
void trpg_byteswap_float_to_4bytes( float number, char result[4] )
{
trpg_swap_four( (const char*) &number, result );
}
/*
** func: tx_byteswap_double_to_8bytes( number )
**
** desc: byte-swaps a double.
*/
void trpg_byteswap_double_to_8bytes( double number, char result[8] )
{
trpg_swap_eight( (const char*) &number, result );
}
/*
** func: tx_byteswap_float( number )
**
** desc: byte-swaps a float.
*/
float trpg_byteswap_4bytes_to_float( const char result[4] )
{
float number;
trpg_swap_four( result, (char*) &number );
return number;
}
/*
** func: tx_byteswap_double_to_8bytes( number )
**
** desc: byte-swaps a double.
*/
double trpg_byteswap_8bytes_to_double( const char result[8] )
{
double number;
trpg_swap_eight( result, (char*) &number );
return number;
}
trpgllong trpg_byteswap_llong ( trpgllong number )
{
trpgllong result;
trpg_swap_sixteen ( (char *) &number, (char *) &result);
return result;
}
trpgEndian trpg_cpu_byte_order(void)
{
static char big_endian_100[2] = { 0, 100 };
if ( (*((short*) big_endian_100)) == 100 )
return BigEndian;
else
return LittleEndian;
}

View File

@@ -0,0 +1,69 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#ifndef trpage_swap_h_
#define trpage_swap_h_
/* trpage_swap.h
Byte swapping utility functions.
*/
#include "trpage_sys.h"
#include "trpage_io.h"
// Byte swap and return a short
// {group:Byte Ordering Utilities}
short trpg_byteswap_short( short number );
// Byte swap and return an integer
// {group:Byte Ordering Utilities}
int trpg_byteswap_int( int number );
// Byte swap and return a long
// {group:Byte Ordering Utilities}
long trpg_byteswap_long( long number );
// Byte swap and return a 64 bit long
// {group:Byte Ordering Utilities}
trpgllong trpg_byteswap_llong ( trpgllong number );
// Byte swap a float value into 4 characters. We do it this way to avoid floating point exceptions.
// {group:Byte Ordering Utilities}
void trpg_byteswap_float_to_4bytes( float number, char result[4] );
// Byte swap a double value into 8 characters. We do it this way to avoid floating point exceptions.
// {group:Byte Ordering Utilities}
void trpg_byteswap_double_to_8bytes( double number, char result[8] );
// Swap 4 bytes into a float and return it
// {group:Byte Ordering Utilities}
float trpg_byteswap_4bytes_to_float( const char result[4] );
// Swap 8 bytes into a double and return it
// {group:Byte Ordering Utilities}
double trpg_byteswap_8bytes_to_double( const char result[8] );
// Determine the current CPU's byte ordering
// {group:Byte Ordering Utilities}
trpgEndian trpg_cpu_byte_order(void);
// Swap two chars
// {group:Byte Ordering Utilities}
void trpg_swap_two ( const char *in, char *out );
// Swap 4 chars
// {group:Byte Ordering Utilities}
void trpg_swap_four ( const char *in, char *out );
// Swap 8 chars
// {group:Byte Ordering Utilities}
void trpg_swap_eight ( const char *in, char *out );
// Swap sixteen chars
// {group:Byte Ordering Utilities}
void trpg_swap_sixteen ( const char *in, char *out );
#endif

View File

@@ -0,0 +1,138 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
/* trpage_sys.h
System specific declarations.
*/
#ifndef trpage_sys_h_
#define trpage_sys_h_
#if defined(_WIN32)
/* *********************
System Specific Section.
This is currently set up for win32.
*********************
*/
#include <windows.h>
// Microsoft Developer warnings that annoy me
#pragma warning ( disable : 4251)
#pragma warning ( disable : 4275)
#pragma warning ( disable : 4786)
// Somewhat system independent file deletion macro
#define TRPGDELETEFILE(file) DeleteFile((file))
#ifndef int64
// 64 bit long value. Need this for really big files.
typedef __int64 int64;
#endif
#else // Unix
#include <stdio.h>
// Delete a file
#define TRPGDELETEFILE(file) remove((file))
//#ifndef int64
//typedef long long int64;
//#endif
#if defined(sgi) && defined(unix)
# include <sgidefs.h>
typedef __int64_t int64;
#elif defined(sun) && defined(unix) && (defined(SUN551) || defined(SUN56))
// NOTE: SUN56 and SUN551 is assumed to be defined in our makefiles.
#include <sys/types.h>
typedef longlong_t int64;
#elif defined(sun) && defined(unix)
// This should work on SunOS 5.7 and later.
#include <sys/types.h>
typedef int64_t int64;
#elif defined(linux)
#include <sys/types.h>
typedef int64_t int64;
//typedef long long int int64;
#elif defined(__ghs__) && defined(__LL_Is_64)
typedef long long int64;
#else
typedef int int64; // DON'T KNOW WHAT TO DO
#endif
#endif
// Basic data types
#ifndef uint8
typedef unsigned char uint8;
#endif
#ifndef int32
typedef int int32;
#endif
#ifndef uint32
typedef unsigned int uint32;
#endif
#ifndef float32
typedef float float32;
#endif
#ifndef float64
typedef double float64;
#endif
// Note: replace this with your own STL implementation
// You can use the Microsoft provided one by deleting the first #include
#ifdef USEROGUE
#include <txRogueWave.h>
#endif
#if defined(WIN32) || defined(_WIN32) || defined(vxw) || (defined(sgi) && defined(_STANDARD_C_PLUS_PLUS)) || (defined(__GNUC__) && (__GNUC__>=2) && (__GNUC_MINOR__>=91))
#include <vector>
#include <map>
namespace std {}
using namespace std;
#else
#include <vector.h>
#include <map.h>
#endif
//#if defined(_WIN32)
//#include <vector>
//#include <map>
//#else
//#include <vector.h>
//#include <map.h>
//#endif
//#if defined(_WIN32) // PJM
//using namespace std;
//#endif
// We use long longs for addresses within a paging file
typedef int64 trpgllong;
// These are used to export classes from a DLL
// Definitely Windows specific
#include "trpage_ident.h"
#include "trdll.h"
#endif

View File

@@ -0,0 +1,415 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_tile.cpp
This source file contains the implementation of trpgTileTable and trpgTileHeader.
You'll need to edit these if you want to add something to the Tile Table (at
the front of an archive) or the Tile Header (at the beginning of each tile).
*/
#include "trpage_geom.h"
#include "trpage_read.h"
/* Write Tile Table
Keeps track of tiles written to disk.
*/
// Constructor
trpgTileTable::trpgTileTable()
{
// numX = numY = numLod = 0;
numLod = 0;
baseName = NULL;
type = External;
}
// Reset function
void trpgTileTable::Reset()
{
if (baseName)
delete baseName;
// center.resize(0);
// tiles.resize(0);
// numX = numY;
numLod = 0;
baseName = NULL;
type = External;
}
// Destructor
trpgTileTable::~trpgTileTable()
{
Reset();
}
// Set functions
void trpgTileTable::SetNumTiles(int nx,int ny)
{
if (nx <= 0 || ny <= 0)
return;
SetNumTiles(nx,ny,1);
}
void trpgTileTable::SetNumTiles(int nx,int ny,int nl)
{
if (nx <= 0 || ny <= 0 || nl <= 0 || nl >= numLod)
return;
lodSizes[nl] = trpg2iPoint(nx,ny);
// tiles.resize(nx*ny*nl,0);
}
void trpgTileTable::SetTile(int nx,int ny,int nl,trpgDiskRef ref)
{
if (nx < 0 || nx >= numX ||
ny < 0 || ny >= numY ||
nl < 0 || nl >= numLod)
return;
type = Local;
// tiles[nl*(numX*numY)+ny*numX+nx] = ref;
}
void trpgTileTable::SetTile(int nx,int ny,trpgDiskRef ref)
{
SetTile(nx,ny,0,ref);
}
void trpgTileTable::SetBaseName(const char *name)
{
if (baseName)
delete baseName;
baseName = new char[(name ? strlen(name) : 0)+1];
strcpy(baseName,name);
type = External;
}
void trpgTileTable::SetCenter(int nx,int ny,int nl,const trpg3dPoint &pt)
{
if (nx < 0 || nx >= numX ||
ny < 0 || ny >= numY ||
nl < 0 || nl >= numLod)
return;
// center[nl*(numX*numY)+ny*numX+nx] = pt;
}
void trpgTileTable::SetCenter(int nx,int ny,const trpg3dPoint &pt)
{
SetCenter(nx,ny,0,pt);
}
// Need the basename when writing an archive
const char *trpgTileTable::GetBaseName() const
{
return baseName;
}
// Validity check
bool trpgTileTable::isValid() const
{
// if (numX == 0 || numY == 0 || numLod == 0)
// return false;
return true;
}
// Write tile table
bool trpgTileTable::Write(trpgWriteBuffer &buf)
{
if (!isValid())
return false;
buf.Begin(TRPGTILETABLE);
#if 0
numTiles = tiles.size();
buf.Add(numX);
buf.Add(numY);
buf.Add(numLod);
for (unsigned int i=0;i<tiles.size();i++) {
buf.Add(tiles[i]);
buf.Add(center[i]);
}
#endif
buf.Add(baseName);
buf.End();
return true;
}
/* **************
Tile Table Read methods
**************
*/
// Get methods
bool trpgTileTable::GetNumTiles(int &x,int &y,int &l) const
{
// if (!isValid()) return false;
x = numX;
y = numY;
l = numLod;
return true;
}
bool trpgTileTable::GetType(int &t) const
{
if (!isValid()) return false;
t = type;
return true;
}
bool trpgTileTable::GetBaseName(char *str,int strLen) const
{
if (!isValid()) return false;
if (type != External) return false;
int len = (baseName ? strlen(baseName) : 0);
strncpy(str,baseName,MIN(len,strLen)+1);
return true;
}
bool trpgTileTable::GetTile(int x,int y,int lod,trpgDiskRef &ref) const
{
if (!isValid() || type != Local) return false;
// Note: fill this in
return false;
}
bool trpgTileTable::GetTile(int x,int y,int lod,char *str,int strLen) const
{
if (!isValid() || type != External) return false;
sprintf(str,"%s\\tile_%d_%d_%d.tpt",baseName,x,y,lod);
return true;
}
bool trpgTileTable::GetCenter(int x,int y,int lod,trpg3dPoint &pt) const
{
if (!isValid() || x < 0 || x >= numX || y < 0 || y >= numY ||
lod < 0 || lod >= numLod)
return false;
// pt = center[lod*(numX*numY)+y*numX+x];
return true;
}
bool trpgTileTable::Read(trpgReadBuffer &buf)
{
// trpg3dPoint pt;
char tmpStr[1024];
try {
type = External; // Note: Read this in
#if 0
buf.Get(numX);
buf.Get(numY);
buf.Get(numLod);
if (numTiles < 0) throw 1;
for (int i=0;i<numTiles;i++) {
buf.Get(diskRef);
buf.Get(pt);
tiles.push_back(diskRef);
center.push_back(pt);
}
#endif
buf.Get(tmpStr,1023);
SetBaseName(tmpStr);
}
catch (...) {
return false;
}
return isValid();
}
/* Tile Header
Each distinct tile (or model) must have a header
which tells you what models and materials are
referenced in that tile.
*/
// Constructor
trpgTileHeader::trpgTileHeader()
{
}
trpgTileHeader::~trpgTileHeader()
{
}
void trpgTileHeader::Reset()
{
matList.resize(0);
modelList.resize(0);
}
// Set functions
void trpgTileHeader::SetMaterial(int no,int id)
{
if (no < 0 || no >= (int)matList.size())
return;
matList[no] = id;
}
void trpgTileHeader::SetModel(int no,int id)
{
if (no < 0 || no >= (int)modelList.size())
return;
modelList[no] = id;
}
// Set functions
void trpgTileHeader::AddMaterial(int id)
{
// Look for it first
for (unsigned int i=0;i<matList.size();i++)
if (matList[i] == id)
return;
// Didn't find it, add it.
matList.push_back(id);
}
void trpgTileHeader::AddModel(int id)
{
for (unsigned int i=0;i<modelList.size();i++)
if (modelList[i] == id)
return;
modelList.push_back(id);
}
void trpgTileHeader::SetDate(int32 d)
{
date = d;
}
// Get methods
bool trpgTileHeader::GetNumMaterial(int32 &no) const
{
if (!isValid()) return false;
no = (int32)matList.size();
return true;
}
bool trpgTileHeader::GetMaterial(int32 id,int32 &mat) const
{
if (!isValid() || id < 0 || id >= (int32)matList.size())
return false;
mat = matList[id];
return true;
}
bool trpgTileHeader::GetNumModel(int32 &no) const
{
if (!isValid()) return false;
no = modelList.size();
return true;
}
bool trpgTileHeader::GetModel(int32 id,int32 &m) const
{
if (!isValid() || id < 0 || id >= (int32)modelList.size())
return false;
m = modelList[id];
return true;
}
bool trpgTileHeader::GetDate(int32 &d) const
{
if (!isValid()) return false;
d = date;
return true;
}
// Validity check
bool trpgTileHeader::isValid() const
{
return true;
}
// Write to a buffer
bool trpgTileHeader::Write(trpgWriteBuffer &buf)
{
unsigned int i;
if (!isValid())
return false;
buf.Begin(TRPGTILEHEADER);
buf.Begin(TRPG_TILE_MATLIST);
buf.Add((int32)matList.size());
for (i=0;i<matList.size();i++)
buf.Add(matList[i]);
buf.End();
buf.Begin(TRPG_TILE_MODELLIST);
buf.Add((int32)modelList.size());
for (i=0;i<modelList.size();i++)
buf.Add(modelList[i]);
buf.End();
buf.Begin(TRPG_TILE_DATE);
buf.Add(date);
buf.End();
buf.End();
return true;
}
// Tile Header CB
// Used to aid in parsing tile header
// We want the tile header to be expandable, so be careful here
class tileHeaderCB : public trpgr_Callback {
public:
void * Parse(trpgToken,trpgReadBuffer &);
trpgTileHeader *head;
};
void * tileHeaderCB::Parse(trpgToken tok,trpgReadBuffer &buf)
{
int32 no,id,date,i;
try {
switch (tok) {
case TRPG_TILE_MATLIST:
buf.Get(no);
if (no < 0) throw 1;
for (i = 0;i < no; i++) {
buf.Get(id);
head->AddMaterial(id);
}
break;
case TRPG_TILE_MODELLIST:
buf.Get(no);
if (no < 0) throw 1;
for (i=0;i<no;i++) {
buf.Get(id);
head->AddModel(id);
}
break;
case TRPG_TILE_DATE:
buf.Get(date);
head->SetDate(date);
break;
default:
// Don't care
break;
}
}
catch (...) {
return NULL;
}
return head;
}
// Read tile header
bool trpgTileHeader::Read(trpgReadBuffer &buf)
{
tileHeaderCB tcb;
trpgr_Parser parse;
tcb.head = this;
parse.AddCallback(TRPG_TILE_MATLIST,&tcb,false);
parse.AddCallback(TRPG_TILE_MODELLIST,&tcb,false);
parse.AddCallback(TRPG_TILE_DATE,&tcb,false);
parse.Parse(buf);
return isValid();
}

View File

@@ -0,0 +1,651 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_warchive.cpp
This source file contains the implementations of trpgwArchive and trpgwGeomHelper.
The Write Archive is used to write TerraPage archives. All its important methods
are virtual, so you shouldn't need to modify any of this code. Simply subclass
and override.
The Geometry Helper is a class that's used to sort out polygons and build
trpgGeometry objects, containing triangle strips and fans out of them. The one
contained here is fairly simple, but all its important methods are virtual. So
again, subclass and override if you need to change them.
*/
#include "trpage_geom.h"
#include "trpage_write.h"
// Constructor
trpgwArchive::trpgwArchive(trpgEndian inNess)
{
fp = NULL;
// Note: only doing external tiles
tileTable.SetBaseName(".");
strcpy(dir,".");
ness = inNess;
cpuNess = trpg_cpu_byte_order();
}
void trpgwArchive::init(trpgEndian inNess)
{
ness = inNess;
}
// Destructor
trpgwArchive::~trpgwArchive()
{
if (fp)
fclose(fp);
}
// IsValid()
// Verifies that our file is open
bool trpgwArchive::isValid() const
{
if (!fp)
return false;
return true;
}
/* Set Functions
These just copy tables and the header from the input.
If these aren't set, then empty ones are written.
*/
bool trpgwArchive::SetHeader(const trpgHeader &head)
{
header = head;
return true;
}
bool trpgwArchive::SetMaterialTable(const trpgMatTable &mat)
{
matTable = mat;
return true;
}
bool trpgwArchive::SetTextureTable(const trpgTexTable &tex)
{
texTable = tex;
return true;
}
bool trpgwArchive::SetModelTable(const trpgModelTable &models)
{
modelTable = models;
return true;
}
// OpenFile
// Same as above, only gets a basename as well
bool trpgwArchive::OpenFile(const char *in_dir,const char *name)
{
char filename[1024];
strncpy(dir,in_dir,1023);
sprintf(filename,"%s/%s",dir,name);
if (!(fp = fopen(filename,"wb")))
return false;
return true;
}
// CloseFile
// Close the open file
void trpgwArchive::CloseFile()
{
if (fp)
fclose(fp);
fp = NULL;
}
/* WriteHeader
For now everything is external, so the header is written last.
The order is this:
Header
Material table
Texture References
Model References
[Future:
Tile Address Table
Model Address Table]
*/
bool trpgwArchive::WriteHeader()
{
trpgMemWriteBuffer buf(ness);
if (!isValid())
return false;
// Write all the headers into a buffer
if (!header.Write(buf) ||
!matTable.Write(buf) ||
!texTable.Write(buf) ||
!modelTable.Write(buf) ||
!tileTable.Write(buf))
return false;
// Write the disk header
int32 magic = TRPG_MAGIC;
if (ness != cpuNess)
magic = trpg_byteswap_int(magic);
if (fwrite(&magic,sizeof(int32),1,fp) != 1)
return false;
// Write the header length
int32 headerSize = buf.length();
int headLen = headerSize;
if (ness != cpuNess)
headerSize = trpg_byteswap_int(headerSize);
if (fwrite(&headerSize,1,sizeof(int32),fp) != sizeof(int32)) return false;
// Write the buffer
const char *data = buf.getData();
if (fwrite(data,sizeof(char),headLen,fp) != (unsigned int)headLen)
return false;
char space[40];
if (fwrite(space,1,4,fp) != 4)
return false;
return true;
}
/* WriteTile
For now we're only doing external tiles.
Note: Do more checking
*/
bool trpgwArchive::WriteTile(unsigned int x,unsigned int y,unsigned int lod,
const trpgMemWriteBuffer *head,const trpgMemWriteBuffer *buf)
{
FILE *tfp=NULL;
if (!isValid())
return false;
// Get the basename and make a new file
const char *base = tileTable.GetBaseName();
if (!base)
return false;
// Make a new filename
char filename[1024];
// Note: Windows specific
sprintf(filename,"%s/%s/tile_%d_%d_%d.tpt",dir,base,x,y,lod);
if (!(tfp = fopen(filename,"wb")))
return false;
// Write the header first
int len;
const char *data;
if (head) {
data = head->getData();
len = head->length();
if (fwrite(data,sizeof(char),len,tfp) != (unsigned int)len) {
fclose(tfp);
return false;
}
}
// Write the buffer out
data = buf->getData();
len = buf->length();
if (fwrite(data,sizeof(char),len,tfp) != (unsigned int)len) {
fclose(tfp);
return false;
}
fclose(tfp);
// Note: Should be updating the center in the tile table
// Also, last updated date
return true;
}
/* DeleteTile
Delete the given tile.
Note: This is system specific.
*/
bool trpgwArchive::DeleteTile(unsigned int x,unsigned int y,unsigned int lod)
{
if (!isValid()) return false;
const char *base = tileTable.GetBaseName();
if (!base) return false;
// Note: windows specific
char filename[1024];
sprintf(filename,"%s\\tile_%d_%d_%d.tpt",base,x,y,lod);
TRPGDELETEFILE(filename);
return true;
}
/* ****************
Geometry Stats
Used by the Geometry Helper
****************
*/
trpgwGeomStats::trpgwGeomStats()
{
totalTri = totalStripTri = totalFanTri = totalBagTri = 0;
for (int i=0;i<15;i++) {
stripStat[i] = fanStat[i] = 0;
}
stripGeom = fanGeom = bagGeom = 0;
stateChanges = 0;
numStrip = numFan = 0;
totalQuad = 0;
}
trpgwGeomStats::~trpgwGeomStats()
{
}
/* ****************
Geometry Helper
Here, since it's used with a write archive.
****************
*/
trpgwGeomHelper::trpgwGeomHelper()
{
buf = NULL;
mode = trpgGeometry::Triangles;
}
trpgwGeomHelper::~trpgwGeomHelper()
{
}
void trpgwGeomHelper::SetMode(int m)
{
if (m == trpgGeometry::Triangles || m == trpgGeometry::Quads)
mode = m;
}
trpgwGeomHelper::trpgwGeomHelper(trpgWriteBuffer *ibuf, int dtype)
{
init(ibuf,dtype);
}
void trpgwGeomHelper::init(trpgWriteBuffer *ibuf,int dtype)
{
buf = ibuf;
dataType = dtype;
}
// Reset back to a clean state (except for the buffer)
void trpgwGeomHelper::Reset()
{
ResetTri();
ResetPolygon();
}
// Reset triangle arrays (usually after a flush)
void trpgwGeomHelper::ResetTri()
{
strips.Reset();
fans.Reset();
bags.Reset();
tex.resize(0);
norm.resize(0);
vert.resize(0);
}
// Start a polygon definition
void trpgwGeomHelper::StartPolygon()
{
ResetPolygon();
}
// Finish a polygon definition
void trpgwGeomHelper::EndPolygon()
{
// See if we can add it to the current triangle arrays
if (vert.size() && (matTri != matPoly)) {
// Couldn't flush geometry and move on
FlushGeom();
}
// Turn the polygon into triangles
// Note: Only dealing with convex here
matTri = matPoly;
switch (mode) {
case trpgGeometry::Triangles:
{
int num = polyVert.size() - 2;
int id1,id2;
for (int i=0;i<num;i++) {
// Note: Handle color
/* Swap 1 and 2 positions
This lets the Optimizer pick up on triangle fans
If you're not using our optimizer this will do very weird things
Probably it will screw up backface culling.
*/
// Note: turned this off because it was broken. Put it back
#if 0
id1 = i+1;
id2 = i+2;
if (num > 1) {
id1 = i+2; id2 = i+1;
}
#else
id1 = i+1;
id2 = i+2;
#endif
// Define the triangle
vert.push_back(polyVert[0]);
vert.push_back(polyVert[id1]);
vert.push_back(polyVert[id2]);
norm.push_back(polyNorm[0]);
norm.push_back(polyNorm[id1]);
norm.push_back(polyNorm[id2]);
tex.push_back(polyTex[0]);
tex.push_back(polyTex[id1]);
tex.push_back(polyTex[id2]);
}
}
break;
case trpgGeometry::Quads:
{
int num = polyVert.size();
if (polyVert.size() == 4) {
for (int i=0;i<num;i++) {
vert.push_back(polyVert[i]);
norm.push_back(polyNorm[i]);
tex.push_back(polyTex[i]);
}
}
}
break;
}
ResetPolygon();
}
// Clean out the polygon arrays
void trpgwGeomHelper::ResetPolygon()
{
matPoly = -1;
polyTex.resize(0);
polyNorm.resize(0);
polyVert.resize(0);
}
// Set the current color
// Note: Required
void trpgwGeomHelper::SetColor(trpgColor &col)
{
// tmpColor = col;
}
// Set the current texture coord
// Note: Required
void trpgwGeomHelper::SetTexCoord(trpg2dPoint &pt)
{
tmpTex = pt;
}
// Set the current normal
// Note: required
void trpgwGeomHelper::SetNormal(trpg3dPoint &pt)
{
tmpNorm = pt;
}
// Set the current material
// Note: required
void trpgwGeomHelper::SetMaterial(int32 imat)
{
matPoly = imat;
}
// Collect the current vertex data and add a new whole vertex
// Note: Deal with color
void trpgwGeomHelper::AddVertex(trpg3dPoint &pt)
{
polyTex.push_back(tmpTex);
polyNorm.push_back(tmpNorm);
// Note: Turn this back on. It's not right currently, though
#if 0
if (buf->GetEndian() != trpg_cpu_byte_order())
{
trpg3dPoint tmpVert;
tmpVert.x = trpg_byteswap_8bytes_to_double ((char *)&pt.x);
tmpVert.y = trpg_byteswap_8bytes_to_double ((char *)&pt.y);
tmpVert.z = trpg_byteswap_8bytes_to_double ((char *)&pt.z);
polyVert.push_back(tmpVert);
}
else
#endif
polyVert.push_back(pt);
}
// Flush the current set of geometry and move on
void trpgwGeomHelper::FlushGeom()
{
bool hadGeom = false;
switch (mode) {
case trpgGeometry::Triangles:
{
Optimize();
// Write only if we've got something
int numPrim;
if (strips.GetNumPrims(numPrim) && numPrim) {
strips.Write(*buf);
stats.stripGeom++;
hadGeom = true;
}
if (fans.GetNumPrims(numPrim) && numPrim) {
fans.Write(*buf);
stats.fanGeom++;
hadGeom = true;
}
if (bags.GetNumPrims(numPrim) && numPrim) {
bags.Write(*buf);
stats.bagGeom++;
hadGeom = true;
}
}
break;
case trpgGeometry::Quads:
{
int numVert = vert.size();
// Make sure we've got quads
if (numVert % 4 == 0) {
int dtype = (dataType == UseDouble ? trpgGeometry::DoubleData : trpgGeometry::FloatData);
// Just dump the quads into single geometry node
trpgGeometry quads;
quads.SetPrimType(trpgGeometry::Quads);
quads.AddTexCoords(trpgGeometry::PerVertex);
for (int i=0;i<numVert;i++) {
quads.AddVertex((trpgGeometry::DataType)dtype,vert[i]);
quads.AddNormal((trpgGeometry::DataType)dtype,norm[i]);
quads.AddTexCoord((trpgGeometry::DataType)dtype,tex[i]);
}
quads.SetNumPrims(numVert/4);
quads.AddMaterial(matTri);
quads.Write(*buf);
stats.totalQuad++;
hadGeom = true;
}
}
break;
}
if (hadGeom)
stats.stateChanges++;
ResetTri();
}
/* Optimize
Form triangle strips and fans and dump the rest into a "bag"
of triangles.
This works for TERREX, but won't do a whole lot for anyone else.
It will produce valid output, but not particularly optimized.
*/
#define ADDVERT(dest,vt) { \
dest.AddVertex((trpgGeometry::DataType)dtype,vt.v); \
dest.AddNormal((trpgGeometry::DataType)dtype,vt.n); \
dest.AddTexCoord((trpgGeometry::DataType)dtype,vt.tex); \
}
class optVert {
public:
optVert() { valid = false; }
optVert(trpg3dPoint iv,trpg3dPoint in,trpg2dPoint itex) { v = iv; n = in; tex = itex; valid = true;}
trpg3dPoint v;
trpg3dPoint n;
trpg2dPoint tex;
bool valid;
int operator == (const optVert &in) const { return (v.x == in.v.x && v.y == in.v.y && v.z == in.v.z &&
n.x == in.n.x && n.y == in.n.y && n.z == in.n.z &&
tex.x == in.tex.x && tex.y == in.tex.y); }
};
void trpgwGeomHelper::Optimize()
{
/*bool isStrip = false;*/
int dtype = (dataType == UseDouble ? trpgGeometry::DoubleData : trpgGeometry::FloatData);
// Potentially writing to all of these
strips.SetPrimType(trpgGeometry::TriStrips);
strips.AddMaterial(matTri);
strips.AddTexCoords(trpgGeometry::PerVertex);
fans.SetPrimType(trpgGeometry::TriFans);
fans.AddMaterial(matTri);
fans.AddTexCoords(trpgGeometry::PerVertex);
bags.SetPrimType(trpgGeometry::Triangles);
bags.AddMaterial(matTri);
bags.AddTexCoords(trpgGeometry::PerVertex);
int numTri = vert.size()/3;
if (numTri == 0)
return;
// Iterate through the triangles
enum {Strip,Fan,Bag};
int type,triId;
optVert a[3],b[3],c[3];
for (triId = 0; triId<numTri; ) {
// Triangle A
int vid = 3*triId;
a[0] = optVert(vert[vid],norm[vid],tex[vid]);
a[1] = optVert(vert[vid+1],norm[vid+1],tex[vid+1]);
a[2] = optVert(vert[vid+2],norm[vid+2],tex[vid+2]);
// If we've got two or more triangles to go, try to form something
if (triId + 1 <numTri) {
// Triangle B
b[0] = optVert(vert[vid+3],norm[vid+3],tex[vid+3]);
b[1] = optVert(vert[vid+4],norm[vid+4],tex[vid+4]);
b[2] = optVert(vert[vid+5],norm[vid+5],tex[vid+5]);
// Is it a triangle strip?
if (a[1] == b[1] && a[2] == b[0])
type = Strip;
else {
// Might be a Fan
if (a[0] == b[0] && a[1] == b[2])
type = Fan;
else
type = Bag;
}
} else
type = Bag;
switch (type) {
case Bag:
ADDVERT(bags,a[0]);
ADDVERT(bags,a[1]);
ADDVERT(bags,a[2]);
bags.AddPrim();
triId++;
stats.AddBagStat(1);
break;
case Strip:
{
bool isStrip,flip=true;
int primLen = 0;
// Dump A into the strip
ADDVERT(strips,a[0]);
ADDVERT(strips,a[1]);
ADDVERT(strips,a[2]);
triId++;
primLen = 3;
do {
// Already checked that B was good on last go-round
ADDVERT(strips,b[2]); primLen++;
triId++;
vid = 3*triId;
if (triId < numTri) {
// B is the new primary, check it against the next
c[0] = optVert(vert[vid],norm[vid],tex[vid]);
c[1] = optVert(vert[vid+1],norm[vid+1],tex[vid+1]);
c[2] = optVert(vert[vid+2],norm[vid+2],tex[vid+2]);
if (flip)
isStrip = (c[0] == b[0] && c[1] == b[2]);
else
isStrip = (c[0] == b[2] && c[1] == b[1]);
b[0] = c[0]; b[1] = c[1]; b[2] = c[2];
}
flip = !flip;
} while (triId < numTri && isStrip);
strips.AddPrimLength(primLen);
stats.AddStripStat(primLen);
}
break;
case Fan:
{
bool isFan;
int primLen = 0;
// Dump A into the Fan
ADDVERT(fans,a[0]);
ADDVERT(fans,a[2]);
ADDVERT(fans,a[1]);
triId++;
primLen = 3;
do {
// Already know that B is good, add that
ADDVERT(fans,b[1]); primLen++;
triId++;
vid = 3*triId;
if (triId < numTri) {
// B is the new primary, check it agains the next
c[0] = optVert(vert[vid],norm[vid],tex[vid]);
c[1] = optVert(vert[vid+1],norm[vid+1],tex[vid+1]);
c[2] = optVert(vert[vid+2],norm[vid+2],tex[vid+2]);
isFan = (c[0] == b[0] && c[2] == b[1]);
b[0] = c[0]; b[1] = c[1]; b[2] = c[2];
}
} while (triId < numTri && isFan);
fans.AddPrimLength(primLen);
stats.AddFanStat(primLen);
}
break;
}
}
}

View File

@@ -0,0 +1,191 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#ifndef _txpage_write_h_
// {secret}
#define _txpage_write_h_
/* trpage_write.h
Classes that are used to write paging archives.
*/
#include "trpage_sys.h"
#include "trpage_io.h"
#include "trpage_swap.h"
/* Geometry Stats
Used with a Geometry Helper to keep track of what go built.
{group:Archive Writing}
*/
TX_EXDECL class TX_CLDECL trpgwGeomStats {
public:
trpgwGeomStats(void);
~trpgwGeomStats(void);
int totalTri; // Total # of triangles
int totalQuad; // Total # of quads
// Add up to totalTri
int totalStripTri; // triangles in strips
int totalFanTri; // triangles in fans
int totalBagTri; // loose triangles
int numStrip; // Number of distinct strips
int numFan; // Number of distinct fans
int stripStat[15]; // Strip length stats
int fanStat[15]; // Fan length stats
int stripGeom; // Number of seperate trpgGeometry nodes for strips
int fanGeom; // Same for fans
int bagGeom; // Same for bags
int stateChanges; // Number of distinct material switches
// Helper functions
inline void AddStripStat(int val) { stripStat[MIN(14,val)]++; totalStripTri += val; totalTri += val; numStrip++;}
inline void AddFanStat(int val) { fanStat[MIN(14,val)]++; totalFanTri += val; totalTri += val; numFan++;}
inline void AddBagStat(int val) { totalBagTri += val; totalTri += val;}
inline void AddQuadStat(int val) { totalQuad++; }
};
/* Geometry Helper
Collects up geometry and tries to form triangle strips, fans,
and groups of triangles.
Right now this looks for a very careful ordering. If that ordering
isn't there you won't get useful tristrips or fans. You can, however
use this class as a starting point and build something more akin
to the geometry builder in Performer.
{group:Archive Writing}
*/
TX_EXDECL class TX_CLDECL trpgwGeomHelper {
public:
trpgwGeomHelper(void);
virtual ~trpgwGeomHelper(void);
enum {UseDouble,UseFloat};
trpgwGeomHelper(trpgWriteBuffer *,int dataType=UseDouble);
void init(trpgWriteBuffer *,int dataType=UseDouble);
virtual void SetMode(int); // Takes a trpgGeometry primitive type (triangle by default)
virtual void Reset();
// Start/End polygon definition
virtual void StartPolygon();
virtual void EndPolygon();
virtual void ResetPolygon(); // If you change your mind about the current poly
// Set the current state
// Note: Currently you *must* set all of these
virtual void SetColor(trpgColor &);
virtual void SetTexCoord(trpg2dPoint &);
virtual void SetNormal(trpg3dPoint &);
virtual void SetMaterial(int32);
// Pull the state info together and add a vertex
virtual void AddVertex(trpg3dPoint &);
// Dump whatever we're doing and move on
virtual void FlushGeom();
// Get statistics for whatever we built
trpgwGeomStats *GetStats() { return &stats; }
protected:
int mode;
int dataType;
trpgWriteBuffer *buf;
/* Builds strips and fans from the triangle array.
We (TERREX) are assuming a certain ordering in our vertex array
because we do this optimization elsewhere. This won't work well
for anyone else. What you will need to do if you want good
performance is to implement a more generic form of this method.
All you should have to do is override Optimize(). You've
got the triangle arrays and a guarantee that the triangles
have the same material. All you really need is a decent fan/strip
algorithm.
*/
virtual void Optimize();
// Reset Triangle arrays
virtual void ResetTri();
// Collections of geometry
trpgGeometry strips,fans,bags;
// Temporary data arrays for triangles/quads
int32 matTri;
vector<trpg2dPoint> tex;
vector<trpg3dPoint> norm,vert;
// Data arrays for a polygon
int32 matPoly;
vector<trpg2dPoint> polyTex;
vector<trpg3dPoint> polyNorm,polyVert;
// Single points
trpg2dPoint tmpTex;
trpg3dPoint tmpNorm;
trpgColor tmpCol;
// Geometry status built up as we go
trpgwGeomStats stats;
};
/* Paging Archive
This is a writeable paging archive.
It organizes where things get written and how.
{group:Archive Writing}
*/
TX_EXDECL class TX_CLDECL trpgwArchive : public trpgCheckable {
public:
trpgwArchive(trpgEndian ness=LittleEndian);
void init(trpgEndian);
virtual ~trpgwArchive(void);
// Set functions. Have to fill all these out before writing
virtual bool SetHeader(const trpgHeader &);
virtual bool SetMaterialTable(const trpgMatTable &);
virtual bool SetTextureTable(const trpgTexTable &);
virtual bool SetModelTable(const trpgModelTable &);
// Note: For now, everything is external
// enum {Local,External};
// virtual bool SetModelMode(int);
// virtual bool SetTileMode(int);
// Write functions.
// For now, the header is written last.
virtual bool OpenFile(const char *,const char *);
virtual void CloseFile(void);
// virtual bool OpenFile(const char *);
virtual bool WriteHeader(void);
virtual bool WriteTile(unsigned int,unsigned int,unsigned int,const trpgMemWriteBuffer *,const trpgMemWriteBuffer *);
virtual bool DeleteTile(unsigned int,unsigned int,unsigned int);
// virtual bool WriteModel(unsigned int,trpgMemWriteBuffer &);
bool isValid(void) const;
char* getDir(){return dir;};
protected:
trpgEndian ness,cpuNess;
// Fed in from the outside
char dir[1024]; // Directory where we're doing all this
trpgHeader header;
trpgMatTable matTable;
trpgTexTable texTable;
trpgModelTable modelTable;
// Used by this class only
trpgTileTable tileTable;
// int modelMode,tileMode;
FILE *fp;
};
#endif

View File

@@ -0,0 +1,286 @@
/* ************************
Copyright Terrain Experts Inc.
Terrain Experts Inc (TERREX) reserves all rights to this source code
unless otherwise specified in writing by the Chief Operating Officer
of TERREX.
This copyright may be updated in the future, in which case that version
supercedes this one.
-------------------
Terrex Experts Inc.
84 West Santa Clara St., Suite 380
San Jose, CA 95113
info@terrex.com
Tel: (408) 293-9977
************************
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* trpage_writebuf.cpp
This source file contains the implementation of trpgMemWriteBuffer.
That is a subclass of trpgWriteBuffer, which implements an interface
definition for an object which can accept data to be written.
The Mem version is used to write (for example) a tile's worth of data.
That data can then be written to a file (or sent over the network).
You should not need to change this implementation. Simply sublcass
trpgWriteBuffer and implement all of the required methods. The
resulting class can then be used in all the places a trpgWriteBuffer
is required.
*/
#include "trpage_io.h"
#include "trpage_swap.h"
/* **********************
Memory Write Buffer functions
**********************
*/
// Constructor
trpgMemWriteBuffer::trpgMemWriteBuffer(trpgEndian in_ness)
{
ness = in_ness;
cpuNess = trpg_cpu_byte_order();
data = NULL;
curLen = totLen = 0;
}
// Destructor
trpgMemWriteBuffer::~trpgMemWriteBuffer()
{
if (data)
delete data;
data = NULL;
}
/* Length()
Return the length of the given buffer.
*/
int trpgMemWriteBuffer::length() const
{
return curLen;
}
/* getData()
Return a pointer to the memory buffer.
*/
const char *trpgMemWriteBuffer::getData() const
{
return data;
}
/* Length()
Set the maximum buffer length.
*/
void trpgMemWriteBuffer::setLength(unsigned int len)
{
if ((int)len > totLen) {
char *old_data = data;
int oldLen = totLen;
totLen = 2*len;
data = new char[totLen];
if (old_data) {
memcpy(data,old_data,oldLen);
delete old_data;
}
}
}
/* append()
Append the given data to our buffer.
*/
void trpgMemWriteBuffer::append(unsigned int len,const char *val)
{
if (len == 0) return;
setLength(curLen+len);
memcpy(&data[curLen],val,len);
curLen += len;
}
/* set()
Set a specific portion of the buffer to a given value.
*/
void trpgMemWriteBuffer::set(unsigned int pos,unsigned int len,const char *val)
{
if (len == 0) return;
if (pos+len > (unsigned int)curLen) return;
memcpy(&data[pos],val,len);
}
/* --- replacement virtual functions --- */
/* Reset()
Drop whatever's being stored.
*/
void trpgMemWriteBuffer::Reset()
{
curLen = 0;
}
// Add(Int32)
void trpgMemWriteBuffer::Add(int32 val)
{
if (ness != cpuNess)
val = trpg_byteswap_int(val);
append(sizeof(int32),(const char *)&val);
}
// Add(int64)
void trpgMemWriteBuffer::Add(int64 val)
{
if (ness != cpuNess)
val = trpg_byteswap_llong(val);
append(sizeof(int64),(const char *)&val);
}
// Add(string)
// [len] [value...]
void trpgMemWriteBuffer::Add(const char *val)
{
int32 len = (val ? strlen(val) : 0),vlen = len;
if (ness != cpuNess)
vlen = trpg_byteswap_int(vlen);
append(sizeof(int32),(const char *)&len);
append(len,val);
}
// Add(float32)
void trpgMemWriteBuffer::Add(float32 val)
{
char cval[4];
if (ness != cpuNess)
trpg_byteswap_float_to_4bytes(val,cval);
else
memcpy(cval,&val,4);
append(sizeof(float32),cval);
}
// Add(float64)
void trpgMemWriteBuffer::Add(float64 val)
{
char cval[8];
if (ness != cpuNess)
trpg_byteswap_double_to_8bytes(val,cval);
else
memcpy(cval,&val,8);
append(sizeof(float64),cval);
}
// Add(int8)
void trpgMemWriteBuffer::Add(uint8 val)
{
// No byte swapping needed
append(sizeof(uint8),(const char *)&val);
}
#if (bool != int32)
// Add(bool)
void trpgMemWriteBuffer::Add(bool val)
{
uint8 ival;
ival = (val ? 1 : 0);
Add(ival);
}
#endif
#if (trpgDiskRef != int64)
// Add(trpgDiskRef)
void trpgMemWriteBuffer::Add(trpgDiskRef val)
{
if (ness != cpuNess)
val = trpg_byteswap_llong(val);
append(sizeof(trpgDiskRef),(const char *)&val);
}
#endif
// Add(trpgToken)
void trpgMemWriteBuffer::Add(trpgToken val)
{
if (ness != cpuNess)
val = trpg_byteswap_short(val);
append(sizeof(trpgToken),(const char *)&val);
}
// Add(tx2iPoint)
void trpgWriteBuffer::Add(const trpg2iPoint &val)
{
Add((int32)val.x);
Add((int32)val.y);
}
// Add(tx2dPoint)
void trpgWriteBuffer::Add(const trpg2dPoint &val)
{
Add((float64)val.x);
Add((float64)val.y);
}
// Add(trpg3dPoint)
void trpgWriteBuffer::Add(const trpg3dPoint &val)
{
Add((float64)val.x);
Add((float64)val.y);
Add((float64)val.z);
}
// Add(trpgColor)
void trpgWriteBuffer::Add(const trpgColor &val)
{
Add(val.red);
Add(val.green);
Add(val.blue);
}
/* Push()
Starts defining a new object.
Need to keep track of where length goes.
*/
void trpgMemWriteBuffer::Begin(trpgToken tok)
{
Add(tok);
lengths.push_back(curLen);
Add((int32)0);
}
/* Push()
Pushes a level on the stack. For defining children.
*/
void trpgMemWriteBuffer::Push()
{
Add((trpgToken)TRPG_PUSH);
}
/* Pop()
Pops a level off the "stack".
*/
void trpgMemWriteBuffer::Pop()
{
Add((trpgToken)TRPG_POP);
}
/* End()
Finished defining an object.
Write the length out where appropriate.
*/
void trpgMemWriteBuffer::End()
{
if (lengths.size() == 0)
// Note: say something clever here
return;
int id = lengths.size()-1;
int32 len = curLen - lengths[id];
int32 rlen = len-sizeof(int32);
if (ness != cpuNess)
rlen = trpg_byteswap_int(rlen);
set(curLen - len,sizeof(int32),(const char *)&rlen);
lengths.resize(id);
}

View File

@@ -9,7 +9,7 @@ Paragraph::Paragraph()
}
Paragraph::Paragraph(const Paragraph& paragraph,const osg::CopyOp& copyop):
Geode(paragraph,copyop),
osg::Geode(paragraph,copyop),
_position(paragraph._position),
_text(paragraph._text),
_font(dynamic_cast<Font*>(copyop(paragraph._font.get()))),