From 4c5fcd3f61d0c7e5bbd1117dcb8c4790ba2f00c5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 8 Feb 2002 09:30:02 +0000 Subject: [PATCH] Fixes for IRIX and Boris Bralo's TerraPage loader. --- AUTHORS | 3 + Makefile | 6 +- VisualStudio/VisualStudio.dsw | 18 + VisualStudio/osgPlugins/txp/txp.dsp | 215 ++++ include/osg/Billboard | 6 +- include/osg/Statistics | 1 + include/osgGLUT/Viewer | 2 +- include/osgText/Font | 2 +- include/osgUtil/RenderStage | 2 +- src/osg/Billboard.cpp | 4 +- src/osgDB/FileNameUtils.cpp | 2 +- src/osgPlugins/Makefile | 2 +- src/osgPlugins/txp/Makefile | 38 + src/osgPlugins/txp/ReaderWriterTXP.cpp | 93 ++ src/osgPlugins/txp/ReaderWriterTXP.h | 50 + src/osgPlugins/txp/TrPageArchive.cpp | 358 ++++++ src/osgPlugins/txp/TrPageArchive.h | 86 ++ src/osgPlugins/txp/TrPageParser.cpp | 533 ++++++++ src/osgPlugins/txp/TrPageParser.h | 162 +++ src/osgPlugins/txp/license.txt | 27 + src/osgPlugins/txp/trdll.h | 117 ++ src/osgPlugins/txp/trpage_basic.cpp | 43 + src/osgPlugins/txp/trpage_geom.cpp | 813 ++++++++++++ src/osgPlugins/txp/trpage_geom.h | 1618 ++++++++++++++++++++++++ src/osgPlugins/txp/trpage_header.cpp | 315 +++++ src/osgPlugins/txp/trpage_ident.h | 21 + src/osgPlugins/txp/trpage_io.h | 484 +++++++ src/osgPlugins/txp/trpage_main.cpp | 31 + src/osgPlugins/txp/trpage_material.cpp | 1184 +++++++++++++++++ src/osgPlugins/txp/trpage_model.cpp | 325 +++++ src/osgPlugins/txp/trpage_nodes.cpp | 640 ++++++++++ src/osgPlugins/txp/trpage_parse.cpp | 266 ++++ src/osgPlugins/txp/trpage_rarchive.cpp | 240 ++++ src/osgPlugins/txp/trpage_read.h | 155 +++ src/osgPlugins/txp/trpage_readbuf.cpp | 430 +++++++ src/osgPlugins/txp/trpage_scene.cpp | 555 ++++++++ src/osgPlugins/txp/trpage_scene.h | 239 ++++ src/osgPlugins/txp/trpage_swap.cpp | 210 +++ src/osgPlugins/txp/trpage_swap.h | 69 + src/osgPlugins/txp/trpage_sys.h | 138 ++ src/osgPlugins/txp/trpage_tile.cpp | 415 ++++++ src/osgPlugins/txp/trpage_warchive.cpp | 651 ++++++++++ src/osgPlugins/txp/trpage_write.h | 191 +++ src/osgPlugins/txp/trpage_writebuf.cpp | 286 +++++ src/osgText/Paragraph.cpp | 2 +- 45 files changed, 11037 insertions(+), 11 deletions(-) create mode 100644 VisualStudio/osgPlugins/txp/txp.dsp create mode 100644 src/osgPlugins/txp/Makefile create mode 100644 src/osgPlugins/txp/ReaderWriterTXP.cpp create mode 100644 src/osgPlugins/txp/ReaderWriterTXP.h create mode 100644 src/osgPlugins/txp/TrPageArchive.cpp create mode 100644 src/osgPlugins/txp/TrPageArchive.h create mode 100644 src/osgPlugins/txp/TrPageParser.cpp create mode 100644 src/osgPlugins/txp/TrPageParser.h create mode 100644 src/osgPlugins/txp/license.txt create mode 100644 src/osgPlugins/txp/trdll.h create mode 100644 src/osgPlugins/txp/trpage_basic.cpp create mode 100644 src/osgPlugins/txp/trpage_geom.cpp create mode 100644 src/osgPlugins/txp/trpage_geom.h create mode 100644 src/osgPlugins/txp/trpage_header.cpp create mode 100644 src/osgPlugins/txp/trpage_ident.h create mode 100644 src/osgPlugins/txp/trpage_io.h create mode 100644 src/osgPlugins/txp/trpage_main.cpp create mode 100644 src/osgPlugins/txp/trpage_material.cpp create mode 100644 src/osgPlugins/txp/trpage_model.cpp create mode 100644 src/osgPlugins/txp/trpage_nodes.cpp create mode 100644 src/osgPlugins/txp/trpage_parse.cpp create mode 100644 src/osgPlugins/txp/trpage_rarchive.cpp create mode 100644 src/osgPlugins/txp/trpage_read.h create mode 100644 src/osgPlugins/txp/trpage_readbuf.cpp create mode 100644 src/osgPlugins/txp/trpage_scene.cpp create mode 100644 src/osgPlugins/txp/trpage_scene.h create mode 100644 src/osgPlugins/txp/trpage_swap.cpp create mode 100644 src/osgPlugins/txp/trpage_swap.h create mode 100644 src/osgPlugins/txp/trpage_sys.h create mode 100644 src/osgPlugins/txp/trpage_tile.cpp create mode 100644 src/osgPlugins/txp/trpage_warchive.cpp create mode 100644 src/osgPlugins/txp/trpage_write.h create mode 100644 src/osgPlugins/txp/trpage_writebuf.cpp diff --git a/AUTHORS b/AUTHORS index 66190a568..b21c52f20 100644 --- a/AUTHORS +++ b/AUTHORS @@ -83,6 +83,9 @@ Paul Fredrikson Phil Atkin - MacOS X port. +Boris Bralo + - txp TerraPage loader. + Sasa Bistrivic - option for detailed calculation of the near clipping plane during cull traversal. diff --git a/Makefile b/Makefile index e20fe8a60..3fd26006c 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/VisualStudio/VisualStudio.dsw b/VisualStudio/VisualStudio.dsw index 99f64c344..43ed264a4 100644 --- a/VisualStudio/VisualStudio.dsw +++ b/VisualStudio/VisualStudio.dsw @@ -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> diff --git a/VisualStudio/osgPlugins/txp/txp.dsp b/VisualStudio/osgPlugins/txp/txp.dsp new file mode 100644 index 000000000..1c28335d8 --- /dev/null +++ b/VisualStudio/osgPlugins/txp/txp.dsp @@ -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 diff --git a/include/osg/Billboard b/include/osg/Billboard index 6b0a4022d..13afb5daf 100644 --- a/include/osg/Billboard +++ b/include/osg/Billboard @@ -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 { diff --git a/include/osg/Statistics b/include/osg/Statistics index ffc8d712e..252ea2ac1 100644 --- a/include/osg/Statistics +++ b/include/osg/Statistics @@ -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) diff --git a/include/osgGLUT/Viewer b/include/osgGLUT/Viewer index 3d73cfb0e..1732c38cf 100644 --- a/include/osgGLUT/Viewer +++ b/include/osgGLUT/Viewer @@ -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: diff --git a/include/osgText/Font b/include/osgText/Font index 4cd8b4241..793eb3f4f 100644 --- a/include/osgText/Font +++ b/include/osgText/Font @@ -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), diff --git a/include/osgUtil/RenderStage b/include/osgUtil/RenderStage index e1f83cb95..1e6f8ab9f 100644 --- a/include/osgUtil/RenderStage +++ b/include/osgUtil/RenderStage @@ -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(obj)!=0L; } virtual const char* className() const { return "RenderStage"; } diff --git a/src/osg/Billboard.cpp b/src/osg/Billboard.cpp index 3c5b9d5d3..ca13b12c3 100644 --- a/src/osg/Billboard.cpp +++ b/src/osg/Billboard.cpp @@ -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 diff --git a/src/osgDB/FileNameUtils.cpp b/src/osgDB/FileNameUtils.cpp index 0ceb7c839..abe7b84bf 100644 --- a/src/osgDB/FileNameUtils.cpp +++ b/src/osgDB/FileNameUtils.cpp @@ -1,7 +1,7 @@ #include #if defined(__sgi) - #include + #include #elif !defined(WIN32) #include using std::tolower; diff --git a/src/osgPlugins/Makefile b/src/osgPlugins/Makefile index 6bdd12cd9..48fbf1e8f 100644 --- a/src/osgPlugins/Makefile +++ b/src/osgPlugins/Makefile @@ -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 diff --git a/src/osgPlugins/txp/Makefile b/src/osgPlugins/txp/Makefile new file mode 100644 index 000000000..bfac62de5 --- /dev/null +++ b/src/osgPlugins/txp/Makefile @@ -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 + diff --git a/src/osgPlugins/txp/ReaderWriterTXP.cpp b/src/osgPlugins/txp/ReaderWriterTXP.cpp new file mode 100644 index 000000000..04a9c99e2 --- /dev/null +++ b/src/osgPlugins/txp/ReaderWriterTXP.cpp @@ -0,0 +1,93 @@ +#include "ReaderWriterTXP.h" +#include "TrPageArchive.h" + +#include +#include +#include +#include + +#include +#include + +#include + +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 g_txpReaderWriterProxy; + diff --git a/src/osgPlugins/txp/ReaderWriterTXP.h b/src/osgPlugins/txp/ReaderWriterTXP.h new file mode 100644 index 000000000..ec533db5e --- /dev/null +++ b/src/osgPlugins/txp/ReaderWriterTXP.h @@ -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 +#include + +#include +#include + +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 diff --git a/src/osgPlugins/txp/TrPageArchive.cpp b/src/osgPlugins/txp/TrPageArchive.cpp new file mode 100644 index 000000000..891edb242 --- /dev/null +++ b/src/osgPlugins/txp/TrPageArchive.cpp @@ -0,0 +1,358 @@ +#include "TrPageArchive.h" +#include "TrPageParser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "trpage_geom.h" +#include "trpage_read.h" +#include "trpage_write.h" +#include "trpage_scene.h" + +#include +#include +#include + +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 = 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 *groupList = parse->GetGroupList(); + + for (int nl=0;nlGetLodSize(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; +} diff --git a/src/osgPlugins/txp/TrPageArchive.h b/src/osgPlugins/txp/TrPageArchive.h new file mode 100644 index 000000000..883d11718 --- /dev/null +++ b/src/osgPlugins/txp/TrPageArchive.h @@ -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 +#include +#include // for auto_ptr +#include "trpage_sys.h" +#include "trpage_read.h" +#include + +#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 parse; + // Texture, material, and model lists. + std::vector< osg::ref_ptr > m_textures; + std::vector< osg::ref_ptr > m_gstates; + std::vector< osg::ref_ptr > m_models; + std::string m_alternate_path; + }; +}; // end namespace + +#endif diff --git a/src/osgPlugins/txp/TrPageParser.cpp b/src/osgPlugins/txp/TrPageParser.cpp new file mode 100644 index 000000000..14cd0f8ee --- /dev/null +++ b/src/osgPlugins/txp/TrPageParser.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TrPageParser.h" +/* +#include +#include +#include +*/ +#include + +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;isetPrimType(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 > &in_mat,vector > &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 +#include +#include +#include +#include +#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 > &, + std::vector > &); + + // 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 >* GetMaterials() { return materials; } + std::vector >* 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 >* materials; + std::vector groupList; + std::vector >* 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 diff --git a/src/osgPlugins/txp/license.txt b/src/osgPlugins/txp/license.txt new file mode 100644 index 000000000..f0ff49448 --- /dev/null +++ b/src/osgPlugins/txp/license.txt @@ -0,0 +1,27 @@ +// +// TerraPage® 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. +// diff --git a/src/osgPlugins/txp/trdll.h b/src/osgPlugins/txp/trdll.h new file mode 100644 index 000000000..3add60cb0 --- /dev/null +++ b/src/osgPlugins/txp/trdll.h @@ -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 diff --git a/src/osgPlugins/txp/trpage_basic.cpp b/src/osgPlugins/txp/trpage_basic.cpp new file mode 100644 index 000000000..be7250261 --- /dev/null +++ b/src/osgPlugins/txp/trpage_basic.cpp @@ -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 +#include + +#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; +} + diff --git a/src/osgPlugins/txp/trpage_geom.cpp b/src/osgPlugins/txp/trpage_geom.cpp new file mode 100644 index 000000000..d6e1f06b1 --- /dev/null +++ b/src/osgPlugins/txp/trpage_geom.cpp @@ -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 +#include +#include + +#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= (int)materials.size()) + return; + + materials[which] = mat; +} +void trpgGeometry::SetMaterials(int32 num,const int32 *mat) +{ + materials.resize(num); + for (int i=0;ifloatData.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= (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= (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= (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 0) { + buf.Begin(TRPG_GEOM_MATERIAL); + buf.Add((int32)materials.size()); + for (i=0;i 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 0) { + buf.Begin(TRPG_GEOM_EFLAG); + buf.Add((int32)edgeFlags.size()); + for (i=0;iSetPrimType((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(); +} diff --git a/src/osgPlugins/txp/trpage_geom.h b/src/osgPlugins/txp/trpage_geom.h new file mode 100644 index 000000000..f1555abc4 --- /dev/null +++ b/src/osgPlugins/txp/trpage_geom.h @@ -0,0 +1,1618 @@ +/* ************************ + 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_geom_h_ +#define trpage_geom_h_ + +/* trpage_geom.h + Geometry and node definitions. + These are the objects that get read from and written to archives. + */ + +#include "trpage_sys.h" + +#include "trpage_io.h" +#include "trpage_swap.h" + +// Forward declarations + +class trpgMaterial; +class trpgTextureEnv; +class trpgMatTable; + +/* This is the archive header structure. There is one per TerraPage archive. + You don't write it directly, but instead fill it out and pass it to + a trpgwArchive (if you're writing), or get it back from a trpgr_Archive + (if you're reading). + If you're putting together a reader, just use the default methods for + reading this class. Since it's only read once, the overhead is low. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgHeader : public trpgReadWriteable { +public: + trpgHeader(void); + ~trpgHeader(void); + + // Set the TerraPage version info. + void SetVersion(int major,int minor); + // Set the database version info. + void SetDbVersion(int major,int minor); + /* Set the tile size for the given LOD. See GetTileSize for more info. + Each LOD must have its size set, otherwise the trpgHeader won't be valid. + You must set the number of LODs with SetNumLods first. + You should use the AddLod method if you can, which handles all of this. + */ + void SetTileSize(int lod,const trpg2dPoint &size); + // Origin defaults to 0,0,0 + void SetOrigin(const trpg3dPoint &); + // 2D archive extents. Must be set. + void SetExtents(const trpg2dPoint &sw,const trpg2dPoint &ne); + + typedef enum {DatabaseLocal,Absolute,TileLocal} trpgTileType; + // How the coordinates are treated with respect to real world values. + void SetTileOriginType(trpgTileType); + + /* Number of terrain LODs. If you use this method when building a database + you have to use the SetLodRange and SetLodSize methods on each LOD as well. + It's better to use AddLod instead of calling these three methods. + */ + void SetNumLods(int); + /* Number of tiles (x,y) for each LOD. + The single argument version assumes lod = 0, num lods = 1. + */ + void SetLodSize(int lod,const trpg2iPoint &); + void SetLodSize(const trpg2iPoint *); + /* Set the range for the given terrain LOD. + The single argument version assumes lod = 0, num lods = 1. + */ + void SetLodRange(int,float64); + void SetLodRange(const float64 *); + // Increase the number of terrain LODs, adding a new one with the given size and range + void AddLod(const trpg2iPoint &size,const trpg2dPoint &ext,float64 range); + + // Keep track of the maximum assigned group IDs (for tile paging) + void SetMaxGroupID(int); + /* Instead of keeping a count of all the group IDs you added and then + calling SetMaxGroupID, you can call this function and it will return + the next valid groupID to you. It will also keep track of the maximum. + */ + int AddGroupID(void); + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // TerraVista version information is two integers. + bool GetVersion(int &,int &) const; + // Database version information is user defined. Put whatever you want here. + bool GetDbVersion(int &,int &) const; + /* This is the extents, in X/Y of a + single tile. All tiles within an LOD should be the same size (although this is not + enforced). It's also assumed that a given tile lives entirely within + its own extents (as calculated with this value), although that's not + enforced either. */ + bool GetTileSize(int,trpg2dPoint &) const; + /* The meaning of the database origin varies depending on the value returned + by GetTileOriginType. If the database is Absolute, then this value + will be the lower left corner. If the database is DatabaseLocal or + TileLocal you can use this value to determine the real world coordinates. + Just add origin + coordinate. + */ + bool GetOrigin(trpg3dPoint &) const; + /* These are the 2D extents that the database covers. You can use this + information to determine where the middle is, for example. + */ + bool GetExtents(trpg2dPoint &sw,trpg2dPoint &ne) const; + /* The tile origin type tells you the coordinate system of each database + tile. There are three type: + * Absolute - All coordinate values are absolute. No translation is required. + * DatabaseLocal - All coordinate values are local to the database. That is + if you want to determine the real world value do: coord + origin. + * TileLocal - Each tile has its own coordinate system starting from the lower left + corner. We do this to get around floating point accuracy problems (although we + can do Double coordinates if necessary, as well). To determine the + real world coordinate value do: tileID*tileSize + coord. + */ + bool GetTileOriginType(trpgTileType &) const; + /* Group IDs are used by TerraPage to hook level of detail structures together. + A TerraPage database can have an arbitrary number of terrain LODs, each stored + seperately. To hook them together we use trpgAttach nodes and number each group & + LOD node. This returns the maximum group ID in the file, which is important + to know if you're keeping an array of them. */ + bool GetMaxGroupID(int &) const; + + /* A TerraPage archive can contain any number of terrain LODs (a typical number is 4). + Each of these terrain LODs is accessed seperately (as are the tiles within them). + This returns the number of terrain LODs in the file. It will be at least 1. + See trpgAttach for instructions on how to hook the terrain LODs together. + */ + bool GetNumLods(int32 &) const; + /* A terrain LOD conceptually covers the entire database and is broken up + into some X x Y set of tiles. We make no assumptions about the number + of tiles in each terrain LOD. That's entirely up to the writer. This + returns the number of tiles in 2D for a given terrain LOD. */ + bool GetLodSize(int32,trpg2iPoint &) const; + /* It's up to the TerraPage archive writer to make their terrain LOD structure + work by using trpgAttach nodes. The scheme they're using may be quad-tree + or replacement LOD or something where the highest LOD isn't even terrain. + It really doesn't matter. However, the reader does need a hint as to + when tiles for a given LOD must be pulled in. This returns that range + in database coordinates (usually meters). + */ + bool GetLodRange(int32,float64 &) const; + + // Read/Write functions + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + // {secret} + bool ReadLodInfo(trpgReadBuffer &); + +protected: + int verMinor,verMajor; + int dbVerMinor,dbVerMajor; + int maxGroupID; + trpg2dPoint sw,ne; + trpg3dPoint origin; + trpgTileType tileType; + + int numLods; + vector tileSize; + vector lodSizes; + vector lodRanges; +}; + +/* The Texture Environment is used by the trpgMaterial to define texture + related parameters. A trpgTextureEnv is associated with each texture + used in a trpgMaterial. So, for example, if there are 2 textures in + a material, there will be two texture environments. + Most of these parameters come straight from the OpenGL specification. It's + best to consult that for an exact meaning. + + If you doing a TerraPage reader, expect to get a trpgTextureEnv when + dealing with trpgMaterial definitions. If you're doing a writer, you'll + need to build these in the course of building a trpgMaterial. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTextureEnv : public trpgReadWriteable { + friend class trpgMatTable; +public: + trpgTextureEnv(void); + ~trpgTextureEnv(void); + + // Environment mode values + enum {Alpha,Blend,Decal,Modulate}; + // Set the application mode for the texture. + void SetEnvMode(int); + // Values used by SetMinFilter and SetMagFilter + enum {Point, Linear, MipmapPoint, MipmapLinear, + MipmapBilinear, MipmapTrilinear, Nearest}; + // Set the Minification filter for a texture + void SetMinFilter(int); + // Set the Magnification filter for a texture + void SetMagFilter(int); + + // Values used by SetWrap + enum {Clamp,Repeat}; + // Set the texture wrapping for S and T, respectively + void SetWrap(int,int); + // Set the texture border color + void SetBorderColor(const trpgColor &); + + /* The environment mode controls how the texture is applied. + It can take the following values: + Alpha - Used to change the alpha values on a polygon. + Blend - Blended with the polygont color + Decal - Doesn't take polygon color into account. + Modulate - See openGL spec for definition. + */ + bool GetEnvMode(int32 &) const; + /* The Minification and Magnification filters control how texture + mipmap levels are used. We support the values: Point, Linear, + MipmapPoint, MipmapLinear, + MipmapBilinear, MipmapTrilinear, Nearest + */ + bool GetMinFilter(int32 &) const; + // Get the magnification filter + bool GetMagFilter(int32 &) const; + /* Wrapping controls how textures are used near the edges. + There are two valid values: Clamp, Repeat. + */ + bool GetWrap(int &,int &) const; + /* This maps straight into the OpenGL definition of border color. */ + bool GetBorderColor(trpgColor &) const; + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + +protected: + int envMode; + int minFilter; + int magFilter; + int wrapS,wrapT; + trpgColor borderCol; +}; + +/* The material definition for TerraPage encompasses those things that have to + do with visual display that can be indexed and disassociated from the + polygons themselves. This covers things like color, texture, alpha + and a few more obscure ones. + Materials are indexed centrally in a trpgMatTable. + + This material definition borrows heavily from the OpenGL specification. + Please refer to that for a good definition of all the fields. + + If you're doing a TerraPage reader you'll need to deal with these in two places. + First, is when you read the archive header and get a trpgMatTable back. You'll + want to translate them into your own internal representation and keep track of + the mapping. Later, when parsing trpgGeometry nodes, you'll run into them + again. This time they will be material indices into a trpgMatTable. At that + point you'll want to map these indices into your own material definition table. + + If you're doing a TerraPage writer you'll need to create one of these for every + unique material-like object you have. Since trpgMaterial objects are indexed + centrally in a TerraPage archive, you should take advantage of that and use + as few as possible. After defining one, you'll want to add it to a trpgMatTable + and keep track of the material index that returns. This will be the mapping from + your own internal material table (or whatever you've got) into the archive's + material table. A trpgMaterial sets up defaults that work pretty well, so just + fill in what you need to use. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgMaterial : public trpgReadWriteable { + friend class trpgMatTable; +public: + trpgMaterial(void); + ~trpgMaterial(void); + // Set base material color + void SetColor(const trpgColor &); + // Ambient color + void SetAmbient(const trpgColor &); + // Diffuse color (the most commonly used) + void SetDiffuse(const trpgColor &); + // Specular color used in lighting + void SetSpecular(const trpgColor &); + // Emissive color used in lighting + void SetEmission(const trpgColor &); + // Shininess used in lighting + void SetShininess(float64); + + enum {Smooth,Flat}; + // Shading model + void SetShadeModel(int); + // Point size + void SetPointSize(float64); + // Line width + void SetLineWidth(float64); + enum {Front,Back,FrontAndBack}; + // Cull mode. See GetCullMode + void SetCullMode(int); + // None and Always appear to be defined on the SGI + // in such a way as to interfere with a local enum + // declaration within a class + enum {trNone,trAlways,Equal,GreaterThanOrEqual,GreaterThan, + LessThanOrEqual,LessThan,Never,NotEqual}; + // Alpha Function. See GetAlphaFunc + void SetAlphaFunc(int); + // Alpha Ref value. See GetAlphaRef + void SetAlphaRef(float64); + // Alpha value for any polygon using this material + void SetAlpha(float64); + // Generate normals automatically from geometry + void SetAutoNormal(bool); + + /* Set the total number of textures used by this trpgMaterial. + This works with SetTexture. We recommend that you used + AddTexture instead of these two methods. */ + void SetNumTexture(int); + /* Works with SetNumTexture. + This method sets the texture ID and texture environment for the given + texture instance in this material. Use AddTexture instead, if you can. + */ + void SetTexture(int no,int id,const trpgTextureEnv &); + /* This method takes a texture ID that refers to a trpgTexTable and a + trpgTextureEnv which specifies the application information relating + to this texture instance. It returns the reference number (i.e. the + 3rd texture in this material, etc...) + */ + int AddTexture(int,const trpgTextureEnv &); + + // Number of tiles this material is used in + void SetNumTiles(int); + // Adds a count to the number of tiles this material is used in and returns that number + int AddTile(); + + // Return the current color + bool GetColor(trpgColor &) const; + // Returns the ambient color + bool GetAmbient(trpgColor &) const; + // Returns the diffuse color (the most commonly used color) + bool GetDiffuse(trpgColor &) const; + // Specular color used for lighting + bool GetSpecular(trpgColor &) const; + // Emissive color used for lighting + bool GetEmission(trpgColor &) const; + // Shininess used for lighting + bool GetShininess(float64 &) const; + + // The shading model can be either Smooth or Flat + bool GetShadeModel(int &) const; + // Point size + bool GetPointSize(float64 &) const; + // Line width + bool GetLineWidth(float64 &) const; + /* Cull mode determines whether geometry will be rejected if it's Front facing, Back + facing, or neither (FrontAndBack) + */ + bool GetCullMode(int &) const; + /* This controls what alpha values in a texture mean. It can take the values: + None,Always,Equal,GreaterThanOrEqual,GreaterThan, + LessThanOrEqual,LessThan,Never,NotEqual + */ + bool GetAlphaFunc(int &) const; + /* The Alpha Ref is a value used in some of the Alpha Functions */ + bool GetAlphaRef(float64 &) const; + // Whether or not to generate normals from geometry + bool GetAutoNormal(bool &) const; + // A single Alpha value that applies to any polygons using this material + bool GetAlpha(float64 &) const; + /* One of the useful things about TerraPage is that it contains enough information + to page textures & materials as well as terrain. This is part of that. + It returns the number of tiles this material is used in. The trpgTexture has + its own which is used for paging textures. You only want to pay attention to + this if you have some costly material definition in your hardware and so have + to swap them in and out. + */ + bool GetNumTile(int &) const; + + /* There can be multiple textures per material. This returns the number. + The first is the base texture, so just use that if you can only do 1 texture per poly. + */ + bool GetNumTexture(int &) const; + /* TerraPage supports multiple textures per polygon. Some hardware can do this, + some can't. If you can support it, here's how this works. + This method returns the texture definition for the Nth texture used in this material. + That consists of a texture ID which points into a trpgTexTable and a trpgTextureEnv + which contains the texture application information. + Multiple materials can also appear per trpgGeometry, so be aware that there are + two ways to have multiple textures per polygon. + */ + bool GetTexture(int no,int &id,trpgTextureEnv &) const; + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + + // Note: Need to do equality operator + +protected: + trpgColor color; + trpgColor ambient; + trpgColor diffuse; + trpgColor specular; + trpgColor emission; + float64 shininess; + int shadeModel; + float64 pointSize; + float64 lineWidth; + int cullMode; + int alphaFunc; + float64 alpha; + float64 alphaRef; + bool autoNormal; + int numTex; + int32 numTile; + vector texids; + vector texEnvs; +}; + +/* There are two levels of materials to save space on disk. + The first level is a regular trpgMaterial. + The second level is a trpgShortMaterial which overrides texture. + This cuts down on header size for geospecific databases. + No one actually sees trpgShortMaterials. You interface with a regular + trpgMaterial. The trpgMatTable figures out when to use these and hides it. + {group:Read/Write Classes} + */ +class trpgShortMaterial { +public: + // Full trpgMaterial definition this one is based on + int32 baseMat; + // Currently the only thing a short material overrides is texture + vector texids; +}; + +/* All materials are centrally indexed in TerraPage. There is one material + table per archive. All trpgGeometry nodes point to that material table (with indices) + for their trpgMaterial definitions. + + The material table has one wrinkle. It is divided up into sub-tables or channels. + Each sub-table has the same number of materials, so there will be NxM trpgMaterial + structures in a trpgMatTable. The sub-tables are intended for use in simple sensor + simulations. For example, the base table (0) is the purely visual, out the window + representation. The next table (1) might the Infra-Red version. It's up to the run-time + system to switch between these two. TerraPage simply provides the means for keeping + track of it. + + If you're doing a TerraPage reader you'll get a trpgMatTable from the trpgr_Archive. + This is your central index for materials. If you can handle the multiple channels/sub-tables + then you can access those as you need. If you can't, just use 0 for the sub-table index where appropriate. + + If you're doing a TerraPage writer you'll need to build up a trpgMatTable to pass to + trpgwArchive. If you're only doing a single sub-table (i.e. visible materials only) + just use AddMaterial and add them as you go. The trpgMaterial object you build up + for a given material are copied when you call the add function. So you can have a single + trpgMaterial, modify just a few fields and call AddMaterial repeatedly. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgMatTable : public trpgReadWriteable { +public: + trpgMatTable(void); + ~trpgMatTable(void); + /* If you intend to have more than one material sub-table you'll + need to set this first before doing anything else. + */ + void SetNumTable(int); + /* This sets the total number of materials. Each sub-table will + have this many of its own materials. If you call this function + you can't use AddMaterial. + */ + void SetNumMaterial(int); + /* Sets a material definition for the given sub-table material ID + combination. If you only have one sub-table you can use + AddMaterial instead. + The two argument version assumes subTable = 0 + */ + void SetMaterial(int subTable,int mat,const trpgMaterial &); + void SetMaterial(int,const trpgMaterial &); + + /* This function should be used if you only have a single material sub-table. + It increases the number of total materials and returns the last material + ID to you. + */ + int AddMaterial(const trpgMaterial &); + + /* Return the number of sub-tables. This will, most commonly, be 1. + Any value more than 1 means the archive has alternate material definitions + (think IR or Radar versions). + */ + bool GetNumTable(int &) const; + /* The number of materials per sub-table. Each sub-table has the same number + of materials. So there will be N x M number of materials total, but you'll + only see M of them at any given time. + */ + bool GetNumMaterial(int &) const; + + /* Returns the material definition for the given subTable and the given material + ID. The most common subTable will be 0 (visual). The material ID comes + from the value(s) in trpgGeometry. + */ + bool GetMaterial(int subTable,int matID,trpgMaterial &) const; + + /* This is a convenience method for getting a reference to a trpgMaterial object. + The reason you might want to do this is if you don't want to create a full + trpgMaterial object to pass to GetMaterial. + The returned value is only valid until the next GetMaterialRef call. + */ + trpgMaterial *GetMaterialRef(int,int); + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + +protected: + int numTable; + int numMat; + vector baseMats; + vector matTables; + trpgMaterial matRef; +}; + +/* This class holds the texture definition TerraPage uses. Textures are a little + different than other TerraPage objects for the following reason: they aren't + stored in the archive. Instead they're stored individually on disk in your + favorite image format. We don't constrain what that format is, although SGI + format (.rgb) is always the safest in this industry. + + Texture objects are really just references to these on-disk textures. As such, + they're pretty simple. They just consist of a filename. These trpgTexture + objects will be indexed in a trpgTexTable. The indices you get from trpgMaterial + objects point to trpgTexture objects through that table. trpgMaterial objects + should be the only things that have texture indices. + + If you're doing a TerraPage reader textures are pretty simple to read in. There + are two ways to do it. First, if you're not doing texture paging, simply read + them all in, using the trpgTexTable to figure out where they all are. If you + are doing texture paging (highly recommended) then you'll need to call GetNumTile + to figure out how many tiles a texture is used in. If it's 1, then this is probably + a geospecific textures and ought to be paged. If it's more than 1, then it's a + geotypical texture (i.e. a tree or road) and should be loaded in at the beginning. + + If you're doing a TerraPage writer you'll need to be creating trpgTexture objects + as you go and adding them to your central trpgTexTable. If you want to support + texture paging set the numTile count to 1 for the geospecific textures and more + than 1 for everything else. There are utility functions for keeping track of all + of this. It's best to use those. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTexture : public trpgReadWriteable { +public: + trpgTexture(void); + trpgTexture(const trpgTexture &); + ~trpgTexture(void); + + // Set the texture name. + void SetName(const char *); + /* This is the texture name. You pass in a string of a pre-defined length + and it returns the texture name in that. */ + bool GetName(char *retStr,int strLen) const; + + /* Sets the number of tiles this texture is used in. This hint is used by + readers to determine texture pageability. */ + void SetNumTile(int); + /* Instead of calling SetNumTile after you've built a database, you can call + AddTile as you encounter each texture reference (per tile). */ + void AddTile(); + + /* This tells you the number of tiles this texture is used in. You can + use this to do texture paging (if you can support it). It's a pretty + general meachanism and will work for large scale geospecific terrain textures + as well as things like specific building pictures. */ + bool GetNumTile(int &) const; + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + + trpgTexture & operator = (const trpgTexture &); + int operator == (const trpgTexture &) const; +protected: + char *name; + int useCount; +}; + +/* The texture table keeps track of all the textures in a TerraPage archive. + All textures are indexed centrally here. The indices in trpgMaterial objects + point into a trpgTexTable. Although the trpgMatTable potentially has several + sub-tables for different representations (visual, IR, etc..), the trpgTexTable + is not affected by that. All textures, no matter what their use, are indexed + together here. + + If you're doing a TerraPage reader you'll get a trpgTexTable back from your + trpgr_Archive. You'll then want to iterate over the trpgTexture objects and + load in the ones used in more than one tile. If you can do texture paging + you should leave the ones only used in 1 tile alone initially. You may also + want to set up a mapping from texture indices here into whatever your own texture + repository is. The texture indices in trpgMaterial objects refer to the listing + here. + + If you're doing a TerraPage writer you'll want to create one of these and add + textures as you go. Textures are copied in when you call AddTexture or SetTexture + so you can reused the trpgTexture object you put together to pass in. The texture + index returned by AddTexture should be used in the trpgMaterial you'll need to build. + Textures don't live in isolation and must be applied to geometry through a trpgMaterial. + After the trpgTexTable is built it will get passed to a trpgwArchive for writing. That + can be done right before you close the archive. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTexTable : public trpgReadWriteable { +public: + trpgTexTable(void); + trpgTexTable(const trpgTexTable &); + ~trpgTexTable(void); + + /* Sets the total number of textures in this table. This is used in + combination with SetTexture. If you can, you should use AddTexture + and FindAddTexture instead. + */ + void SetNumTextures(int); + /* Adds the given texture to the table and increments the total texture + count. If you use this, you should not use SetNumTextures and SetTexture. + */ + int AddTexture(const trpgTexture &); + /* This is the same as AddTexture except that it searches for a matching texture + first. This is convenient for writers who aren't keeping track of their + own textures internally. + */ + int FindAddTexture(const trpgTexture &); + /* This sets the given texture ID to be the trpgTexture passed in. It's used + in combination with SetNumTextures. Use AddTexture or FindAddTexture instead + if you can. + */ + void SetTexture(int texID,const trpgTexture &); + + // Returns the number of textures in this table + bool GetNumTextures(int &) const; + // This returns the trpgTexture corresponding to the given ID (from a trpgMaterial) + bool GetTexture(int texID,trpgTexture &) const; + /* Does the same thing as GetTexture only it returns a pointer instead. + You would use this if you don't want a new trpgTexture created for you. + Assume the value it returns is only good until the next GetTextureRef call. + */ + trpgTexture *GetTextureRef(int); + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + + trpgTexTable & operator = (const trpgTexTable &); +protected: + vector texList; +}; + +/* Models are basically just references in TerraPage. This class just points + to a model from somewhere else. There are two places it can point. (1) It + can point externally to a model in some arbitrary format (OpenFlight(tm) is + a popular one). (2) It can also point to a model within the TerraPage archive. + The first case is much like trpgTexture objects are treated. That is, the actual + thing itself is on disk somewhere corresponding to a file name. The second case is + more like tile terrain geometry. In that case there is scene node type data (LODs, + groups, geometry, etc...) associated with it. + + trpgModel objects live within a trpgModelTable. They are indexed there and refered + to by trpgModelRef objects. Those model references are the only things that explicitly + use trpgModel objects. + + If you're doing a TerraPage reader you'll need to take into account whether the + model is external or internal. If it's external you'll need to read the given file + and convert it to your own representation. If it's internal you've probably already + got the code for dealing with terrain tiles, which is essentially the same thing. + Models can be paged, if you're so inclined. They have tile reference counts just + like trpgTexture objects. If numTile == 1 then page it, if > 1 then don't. + + If you're doing a TerraPage writer you'll want to build up a trpgModelTable of these + as you encounter them. If your models are external in some other format then setting + up a trpgModel is pretty easy. If you want to do internal models, the support is not + quite there yet. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgModel : public trpgReadWriteable { +public: + trpgModel(void); + trpgModel(const trpgModel &); + ~trpgModel(void); + enum {Local,External}; + // Sets the name of the external model file and sets this model to External type. + void SetName(const char *); + // Sets the on-disk reference to an internal model and sets this model to Internal type. + void SetReference(trpgDiskRef); + /* Models are reference counted (per-tile). It's up to the writer to set this + value. */ + void SetNumTiles(int); + /* TerraPage writers can use AddTile (starts at 0) every time they use this model + in a tile. Note that this is not for every instance within a tile. So if + you use a model 40 times within a tile, you call AddTile once. + This is used instead of SetNumTiles. */ + void AddTile(); + + /* Returns the type (Local or External) of this model */ + bool GetType(int &); + /* If the model is external, this returns the file name of that model. + You pass in a string and a length and it copies the filename into that. */ + bool GetName(char *ret,int strLen) const; + /* If the model is internal, this returns the disk reference to it. + At some future data you'll be able to simply read these out of an archive. */ + bool GetReference(trpgDiskRef &) const; + /* Models are reference counted, like trpgTexture objects. You can use this + value to determine whether or not you should page models. + */ + bool GetNumTiles(int &) const; + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + + trpgModel & operator = (const trpgModel &); + int operator == (const trpgModel &) const; +protected: + int type; + char *name; + trpgDiskRef diskRef; + int useCount; +}; + +/* Models (trpgModel) are indexed together in a model table. There is one + model table per TerraPage archive. It holds the canonical list of models + for the entire database. It's pretty simple. Just a list of models, really. + the trpgModel object holds the real information. + + If you're doing a TerraPage reader you'll get one of these from a trpgr_Archive. + You'll want to iterate over the models in it and figure out which ones to page, + if you're doing model paging. If not, then you can just read them all in + at initialization time and index them as need per-tile. + + If you're doing a TerraPage writer you'll build one of these up for the entire + database as you go. Just call AddModel every time you finish a model definition. + The finished table will be passed to trpgwArchive at the end. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgModelTable : public trpgReadWriteable { +public: + trpgModelTable(void); + ~trpgModelTable(void); + + /* Set the total number of models in the table. Use this in conjunction + with SetModel. If you can, use AddModel isntead of either of these. + */ + void SetNumModels(int); + /* Add the given model to the table. Makes a copy of the model you pass in + and returns the new model ID which you'll need to reference in trpgModelRef. + */ + int AddModel(const trpgModel &); + /* Sets the model definition corresponding to the given ID. Use this in conjunction + with SetNumModels. */ + void SetModel(int,const trpgModel &); + + // Returns the number of models in this table + bool GetNumModels(int &) const; + /* Returns the Nth model. trpgModelRef objects point into this table + and that is where the model ID comes from. */ + bool GetModel(int modID,trpgModel &) const; + + /* The same as GetModel only it returns a pointer to the trpgModel instead. + Use this if you don't want to create a copy of the model. + The result is only good until the next GetModelRef call. + */ + trpgModel *GetModelRef(int); + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + +protected: + vector models; +}; + +/* The tile table keeps track of tile locations within a TerraPage archive. + At the present time archives are broken out into multiple files. When + it becomes possible to combine an archive into a single file then this + object will become important. For now, you can safely ignore it.. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTileTable : public trpgReadWriteable { +public: + trpgTileTable(void); + ~trpgTileTable(void); + enum {Local,External}; + void SetNumTiles(int,int); + void SetNumTiles(int,int,int); + void SetBaseName(const char *); + void SetTile(int,int,int,trpgDiskRef); + void SetTile(int,int,trpgDiskRef); + void SetCenter(int,int,int,const trpg3dPoint &); + void SetCenter(int,int,const trpg3dPoint &); + + bool GetNumTiles(int &,int &,int &) const; + // Local or external tiles + bool GetType(int &) const; + bool GetBaseName(char *,int len) const; + // Get the disk reference (local) + bool GetTile(int,int,int,trpgDiskRef &) const; + // Generate the file name (external) + bool GetTile(int,int,int,char *,int len) const; + bool GetCenter(int,int,int,trpg3dPoint &) const; + + const char *GetBaseName(void) const; + + // Validity check + bool isValid(void) const; + // Reads this class from a read buffer + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); +protected: + int type; + int numLod,numX,numY; + vector lodSizes; + +// vector tiles; +// vector center; + + char *baseName; +}; + +/* The tile header is one of the more interesting parts of TerraPage. Basically, + it's a list of all the materials and models used in a tile. Tile headers are + stuck at the beginning of terrain tiles to give you this information. They + can be read separately, in theory, although no one is doing that at present. + + If you're doing a TerraPage reader you will encounter one of these first thing + when you parse a terrain tile. If you're doing texture paging you'll want to get + the list of material IDs, consult those materials and compile a list of texture + IDs that you need loaded in. You can then load those textures in (if necessary) + and go from there. If you're paging models, you can do something similar with + the model list. In theory, the trpgTileHeader is not required for every tile. + If you don't encounter one when reading a tile you'd better assume that everything + needs to be loaded (i.e. texture/model paging is not supported). + + If you're doing a TerraPage writer you will need to construct one of these for + each tile that you build (remember that tiles are per-terrain LOD). You'll want + to call AddMaterial for every material that you use in a tile and AddModel + for every model. You can call these methods multiple times and it will keep track + of whether you've already added a model or material. The tile header will then + be passed to trpgwArchive along with the tile geometry and written to disk. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTileHeader : public trpgReadWriteable { +public: + trpgTileHeader(void); + ~trpgTileHeader(void); + /* Add the given material reference to this tile if it's not already there. + The ID passed in refers to a trpgMatTable. */ + void AddMaterial(int); + /* Add the given model reference to this tile if it's not already there. + The ID passed in refers to a trpgModelTable. */ + void AddModel(int); + // {secret} + void SetDate(int32); + + void SetMaterial(int no,int id); + void SetModel(int no,int id); + + // Returns the number of materials used in this tile + bool GetNumMaterial(int32 &) const; + /* Return the material ID of the Nth material reference. + The ID returned points into a trpgMatTable. */ + bool GetMaterial(int32 nth,int32 &matID) const; + // This is the number of models used in this tile + bool GetNumModel(int32 &) const; + /* Gets the model ID of the Nth model reference. + The ID returned points into a trpgModelTable. */ + bool GetModel(int32 nth,int32 &modID) const; + // {secret} + bool GetDate(int32 &) const; + + // Validity check + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); +protected: + vector matList; + vector modelList; + int date; +}; + +/* The color info structure is used by the trpgGeometry class to store + per vertex (or per primitive) color information. It can be read directly + by the user (all its data is public). This structure is returned by + trpgGeometry::GetColorSet(). + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgColorInfo { +public: + trpgColorInfo(void); + ~trpgColorInfo(void); + + /* This is a trpgGeometry::ColorType + */ + int type; + /* This refers to how the colors in the data array are used. + It can take the values "Overall", "PerPrim" or "PerVertex". + */ + int bind; + /* The list of colors. There will be one total (bind=Overall), one per + primitive (bind=PerPrim), or one per vertex (bind=PerVertex). + */ + vector data; + /* Resets the structure to a default state. + */ + void Reset(void); +}; + +/* This class represents a group of texture coordinates applied to a trpgGeometry + class. It is returned by trpgGeometry::GetTexCoordSet. TerraPage supports + multiple materials per polygon. The way we implement this is as multiple + materials on a trpgGeometry node. The first material with be the "primary" + and additional ones will be secondary and so on. + To support this, we need multiple sets of texture coordinates. That's what + this structure is used for. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTexData { +public: + trpgTexData(void); + ~trpgTexData(void); + // This should always be set to PerVertex + int bind; + /* List of texture coordinates in 32 bit floating point. + There should be one per vertex. Either this or doubleData will be + set, but never both. + */ + vector floatData; + /* List of texture coordinates in 64 bit floating point. + There should be one per vertex. Either this or floatData will be + set, but never both. + */ + vector doubleData; + /* Initialize the texture coordinate data set with floating point or double values. + num should correspond to the correct bind. */ + void set(int num,int bind,const float32 *); + void set(int num,int bind,const float64 *); + /* Resets the structure to a default state. + */ + void Reset(void); +}; + +/* The trpgGeometry class represents a low level geometry node within the + TerraPage "scene graph". This is where the triangles (or quads, polygons, etc...) + are actually kept. If you're writing a TerraPage reader, you'll encounter a + lot of these nodes. If you're doing a writer, you'll need to construct them. + You can use a trpgwGeomHelper to aid you in this process. + We use data arrays to store lists of vertices, colors, texture coordinates, and + normals. These data arrays correspond pretty closely to the respective OpenGL + equivalents. + + In general, you'll want to do a GetPrimType() to figure out what primitive + type (PrimType) a given node is holding. It will typically be TriStrips, + TriFans, or Triangles, but all the other types are valid as well. + The next step is to get the vertices via a GetVertices() call and then get + the normals and texture coordinates (via GetNormals() and GetTexCoordSet() calls). + To get the material information call GetNumMaterial() (if you can support more + than one texture per polygon) and then GetMaterial() for each material. If you + only support one material/texture per polygon then just do one GetMaterial() all. + There's always guaranteed to be at least one material. + + It's a good idea to review the OpenGL specification for triangle arrays and + such before diving into this structure. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgGeometry : public trpgReadWriteable { +public: + trpgGeometry(void); + ~trpgGeometry(void); + typedef enum {Points,LineStrips,LineLoops,Lines,Polygons,TriStrips, + TriFans,Triangles,QuadStrips,Quads} PrimType; + // Set the primitive type for the geometry node + void SetPrimType(PrimType type); + /* Some primitive types require lengths. These include TriStrips and + TriFans, but not Triangles, for example. */ + void SetPrimLengths(int,const int *); + /* Add a primitive length on to the end of the current primLength array. + Use this if you're adding geometry one vertex at a time. + */ + void AddPrimLength(int); + /* This just increments the number of primitives in the structure. Use this + if you're adding geometry one vertex at a time for a Triangle array, for example. + */ + void AddPrim(); + /* Set the total number of primitives. You would use this only when the PrimType + does not require primitive lengths (e.g. Triangles, but not TriStrips). Use + SetPrimLengths() or AddPrimLength() in that case. + */ + void SetNumPrims(int); // Only when there are no primitive lengths + /* This function sets the total number of materials applied to this group + of geometry. If you're only using one material, trpgGeometry defaults to + 1, so you can just do a SetMaterial() and ignore this. + */ + void SetNumMaterial(int); + /* Set the given material instance (in this trpgGeometry node) to the given + material ID. The material ID is an index into a trpgMatTable. You would + need to do a SetNumMaterial() call first, before any number of SetMaterial() + calls if there is more than one material. If there is only one material, + you can do a single SetMaterial(0,MatID) call. + */ + void SetMaterial(int which,int matID); + /* This is the same as repeated SetMaterial() calls. + */ + void SetMaterials(int32 numMat,const int32 *matIDs); + /* This adds the given material ID to the end of the material list. + You can use this instead of SetNumMaterial() and SetMaterial(). + */ + int AddMaterial(int matID); + + // These are primitive types used within the trpgGeometry structure. + enum {VertexFloat,VertexDouble,NormalFloat,NormalDouble, + Color,TextureFloat,TextureDouble,EdgeFlag}; + + /* Used to tell some of the trpgGeometry methods what kind of + data they're getting */ + typedef enum {FloatData,DoubleData} DataType; + + /* The SetVertices() methods will set either 32 or 64 bit floating + point vertex arrays within the trpgGeometry structure. + The num passed in is the number of vertices, not the number of individual + floats or doubles (as with GetNumVertex). + */ + void SetVertices(int num,const float32 *); + void SetVertices(int num,const float64 *); + /* This method will add a vertex to the end of the appropriate data array + (either float or double, but never both). You would use this method + if you were building up a trpgGeometry structure vertex by vertex. + */ + void AddVertex(DataType type,trpg3dPoint &); + /* Binding type used by colors, normals, and textures (just PerPrim). + */ + typedef enum {Overall,PerPrim,PerVertex} BindType; + /* The SetNormals() methods will set either the 32 or 64 bit floating + point normal arrays within the trpgGeometry structure. + The num of normals is determined by the bind type. You should + either set the 32 or 64 bit floating point arrays, but not both. + num is the number of individual normals, not float values, unlike + the GetNumNormal() call. + */ + void SetNormals(int num,BindType bind,const float32 *); + void SetNormals(int num,BindType bind,const float64 *); + /* This method is used to add normals one by one of the given type. + You would use this if you were adding geometry one vertex at a time + in conjuntion with AddVertex(). + */ + void AddNormal(DataType type,trpg3dPoint &); + /* This constant is used to select the type of a color array + passed to SetColors(). + */ + typedef enum {Ambient,Diffuse,Specular,Emission} ColorType; + /* This method sets an array of color structures for a trpgGeometry node. + The num should correspond to the bind type. You can set as many of + these color arrays as you like, they're simply stored in an array for + later use. + */ + void SetColors(int num,ColorType type,BindType bind,const trpgColor *); + /* The SetTexCoords() methods set a list of texture coordinates. This + essentially builds a trpgTexData class and pushes it onto the current + list of texture coordinate sets. Choose the appropriate method based + on 32 or 64 bit floating point values. num should be the number of + texture coordinates, not the number of floats passed in. + + bind should be PerPrim in all cases. + */ + void SetTexCoords(int num,BindType bind,const float32 *); + void SetTexCoords(int num,BindType bind,const float64 *); + /* This is the same as SetTexCoords(0,bind,NULL) */ + void AddTexCoords(BindType bind); + /* This method adds a texture coordinate to array 0. You would use + this if you were adding vertices one at a time. + */ + void AddTexCoord(DataType type,trpg2dPoint &); + /* Edge flags are used by some primitives in OpenGL. We don't typically + use them, but they can be read and written with TerraPage. + */ + void SetEdgeFlags(int num,const char *); + + /* Returns the primitive type for this trpgGeometry structure. + */ + bool GetPrimType(PrimType &type) const; + /* Number of primitives in this structure. Primitives are things + like a single triangle, a triangle strip or fan. Some primitives + require a primitive length array. + */ + bool GetNumPrims(int &num) const; + /* This returns the primitive length array. Some primitive types, like + TriStrips or TriFans (but not Triangles) require a primitive length + array to tell you how to break up the vertex/normal/texture/color + arrays into individual primitives. The array you pass in must be + of a certain length (returned by GetNumPrims()) and will only be + valid for some primitive types. + */ + bool GetPrimLengths(int *lenArray) const; + /* TerraPage supports multiple materials per geometry set. This method + tells you how many are applied to this structure. There will always + be at least one. + */ + bool GetNumMaterial(int &num) const; + /* Returns the material ID for a material instance. num is the + nth material instance. matId is an index into a trpgMatTable. + */ + bool GetMaterial(int num,int32 &matID) const; + /* This returns 3 * num_vertex. The function returns the length + of the vertex array, which is, unfortunately, 3 times the number + of vertices. This is a bug, but isn't likely to be fixed any time + soon. For now, just divide this number by 3. + */ + bool GetNumVertex(int &num) const; + /* The GetVertices() methods return a list of vertices in the given + form (32 or 64 bit floating point). These functions will convert to + the appropriate format, just ask for the one you need. + The length of the vertex array is determined by GetNumVertex(), which + returns 3* the number of vertices. + */ + bool GetVertices(float32 *) const; + bool GetVertices(float64 *) const; + /* This method lets you get an individual vertex. The number of vertices + can be determined by GetNumVertex()/3. + */ + bool GetVertex(int id,trpg3dPoint &) const; + /* GetNumNormal() returns the number of normals * 3. See GetNumVertex() + for an explanation of why. + */ + bool GetNumNormal(int &num) const; + /* Much, like GetVertices(), these methods will copy the contents of + the normal array into the array passed in. They will convert the + contents to the appropriate format (32 or 64 bit floating point). + The length of the input array can be determined by GetNumNormal(). + */ + bool GetNormals(float32 *) const; + bool GetNormals(float64 *) const; + /* This returns the number of color sets in the trpgGeometry structure. + There can be one color set per ColorType. + */ + bool GetNumColorSets(int &num) const; + /* You pass a trpgColorInfo into this method and it will fill it out + + */ + bool GetColorSet(int id,trpgColorInfo *) const; + bool GetNumTexCoordSets(int &) const; + bool GetTexCoordSet(int id,trpgTexData *) const; + bool GetNumEdgeFlag(int &num) const; + bool GetEdgeFlags(char *) const; + + // Returns true if the trpgGeometry structure is valid + bool isValid(void) const; + // Resets the contents back to empty + void Reset(void); + + // Write self to a buffer + bool Write(trpgWriteBuffer &); + // Read self from a buffer. Check isValid() afterwards + bool Read(trpgReadBuffer &); + +protected: + int primType; + int numPrim; + vector primLength; + vector materials; + vector vertDataFloat; + vector vertDataDouble; + int normBind; + vector normDataFloat; + vector normDataDouble; + vector colors; + vector texData; + vector edgeFlags; +}; + +/* This is a standard Group that you might see in any reasonable + scene graph. It holds a number of children. TerraPage isn't + actually a scene graph, it just represents one. That means that there + are no pointers to children here. Instead you'll encounter this group + while reading a terrain tile or model. That tells you to create a group + (or whatever you call it) in your own system and get read to dump child + trees into it. A push will follow this object, then the children (however + deep they may be) then a pop. + + All groups have IDs. These IDs are unique among groups and group-like things + (i.e. LODs) and are used to hook trpgAttach geometry into a scene graph hierachy + as you page in higher terrain levels of detail. + + If you're doing a TerraPage reader, the group tells you to put together + your generic container in a scene graph and get read for the push/children/pop. + The NumChild field should tell you how many children will follow, but a writer + can easily forget to put it, so be wary. You'll also want to look at the group + ID and build a mapping from that ID (look at the max group ID in trpgHeader) to + your own group structure. A trpgAttach is allowed to page itself into any group. + + If you're doing a TerraPage writer you'll create one of these, fill out the + numChild hint, the group ID and then write it. You'll then write a Push, then + the children hierarchies (which can be anything) followed by a Pop. You'll want + to keep track of the group ID you assigned in case one of the children is a + pageable chunk of terrain hierarchy. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgGroup : public trpgReadWriteable { +public: + trpgGroup(void); + ~trpgGroup(void); + // Resets the contents back to empty + virtual void Reset(void); + + /* Set the total number of children this group will have */ + virtual void SetNumChild(int); + // Starting from 0, increments the number of children + virtual int AddChild(void); + /* The writer is supposed to set this value to the number of + children. */ + virtual bool GetNumChild(int &) const; + + /* Set the group ID */ + virtual void SetID(int); + // Returns the group ID + virtual bool GetID(int &) const; + + // Validity check + virtual bool isValid(void) const; + // Writes this class to a write buffer + virtual bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + +protected: + int id; + int numChild; +}; + +/* Structurally, an attach is just like a trpgGroup. It does everything a group + does, plus a little bit more. The attach node is how TerraPage does terrain + database paging across LODs. + + In TerraPage we don't enfoced a terrain LOD structure. Let's say you built + your database as a quad-tree. That is, there is one root tile per block, + 4 children, each of which has 4 of its own children etc... That would imply + a certain structure (4 children per tile until you reach the bottom). That would + also lock you into a database scheme (quad-tree). However, let's assume that + someone else wanted to do replacement LOD for their terrain. That scheme works + by having one child per tile. If you want to support both of these then you're + asking the reader to do a lot of thinking and you can pretty much assume that the + one you don't test won't work. We decided to avoid all that by coming up with a + generic scene graph paging scheme. It's a little more painfull, but once you deal + with it you get whatever weird scheme the writer is using for free without having to + think about it. + + Here's how it works. Each trpgGroup and group-like structure (trpgLod for example) + has a unique group ID. You can have one trpgAttach at the start of a given terrain + tile. That trpgAttach can point to any group within the scene graph (with a group ID). + Level of detail for the terrain is controlled by trpgLod nodes as if everything was + loaded in all the time. That is, you'll see the same thing no matter whether every node + is loaded into memory or just the nearby ones. The theoretical scene graph structure + is the same no matter what. It's the ranges in your trpgHeader that tell you when + things ought to be loaded in, but the actual display logic is contained within the trpgLod + objects. It sounds complicated and it is... for the writer. But for the reader it's + really simple. + + If you're doing a TerraPage reader all you'll need to do is keep a mapping from group + ID's to your own internal scene graph node representation. Then when a trpgAttach shows + up you can turn it into your own group-like thing and stuff it and its children into + the scene graph. When it wanders out of range (the trpgHeader tells you that for a given + terrain LOD) you simply delete it. If you out-run your paging you've got two options: + (1) Display holes. That's what will happen when the LOD above a given tile trpgAttach + turns on without the children in memory; or (2) Don't switch LODs that don't have all + their children loaded in yet. Be aware that a trpgAttach inherits from trpgGroup and + so can have trpgAttach children. So don't absorb the trpgAttach even though it's extra + hierarchy. Also, don't make any assumptions that there is really terrain in a given + tile. The writer may have chosen to page buildings or trees. You never know and there's + no reason to assume. + + If you're doing a TerraPage writer this is slightly more complex than writing a normal + format, depending on the structure of your internal scene graph. If you don't want + to write more than one pageable terrain LOD you can just ignore trpgAttach nodes. This + doesn't mean you can only have one terrain LOD, it only means they won't be pageable. + If you do want to fully support it, what you'll need to + do is give all your groups (or whatever will become groups) unique IDs, keeping in mind + to update the trpgHeader max group ID as you go. Start at the lowest terrain lod. This + one doesn't need to have a trpgAttach node since it's at the top. Traverse toward + the higher lods. When you hit one, spit out a trpgAttach, giving it the group ID of + the trpgGroup directly above it. Then treat the node you just created as a trpgGroup + (i.e. do its children as normal). You will also need to keep the trpgTileHeader for + each tile around. It's best to index these by (x,y,lod) index. You'll need to build + that tile header up *just for this tile geometry*. That means you have to stop adding + material/model references when you start defining the next tile. Depending on how you + write out your scene graph it may make sense to keep a stack of trpgTileHeader and + trpgMemWriteBuffer objects around indexed by tile (x,y,lod). + + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgAttach : public trpgGroup { +public: + trpgAttach(void); + ~trpgAttach(void); + // Resets the contents back to empty + void Reset(void); + + // Set the parent of the group/LOD/whatever to attach to when loaded in + void SetParentID(int); + // Retrieve the parent ID we'll need to attach this thing into the scene graph + bool GetParentID(int &) const; + + /* The writer is supposed to set this value to a unique position with relation + to its parent group. */ + void SetChildPos(int); + /* The child position is a hint as to which child this is in its parent group. + That is, if there are 3 children, of which this is one, then it could be + at child position 0, 1, or 3 in its parent. You can safely ignore this if + you want to just this node to its parent's list of children. */ + bool GetChildPos(int &) const; + + // Validity check + virtual bool isValid(void) const; + // Writes this class to a write buffer + virtual bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + +protected: + int parentID,childPos; +}; + +/* The billboard inherits from the standard trpgGroup. It tells the reader that + everything underneath this node is supposed to be treated like a stamp or billboard + (depending on your terminology). That means it's supposed to be rotated towards + the eye point in some way. There are no restrictions on the number, depth, or type + of children. In theory you could have another billboard as a child, although we have + no idea what that should look like. + + If you're doing a TerraPage reader treat everything underneath this group as rotatable. + Pay attention to the Type in particular. There's a shorthand for rotating a bunch + of objects that is a little confusing. + + If you're doing a TerraPage write this is pretty simple. For the standard tree example + use one of these with one or more trpgGeometry children. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgBillboard : public trpgGroup { +public: + trpgBillboard(void); + ~trpgBillboard(void); + enum {Individual,Group}; + // Set the type. See GetType for details. + void SetType(int); + // Set the center. + void SetCenter(const trpg3dPoint &); + enum {Axial,World,Eye}; + // Set the rotation mode. + void SetMode(int); + // Set the rotation axis if mode == Axial + void SetAxis(const trpg3dPoint &); + + /* The type controls how the billboard node relates to its children. There + are two modes: (1) Group - This is the obvious one. Everything below + this node rotates around the center in the way specified by GetMode. (2) Individual - This + is a little weirder. Basically, it's here for trees. It's assumed that + there will be one or more trpgGeometry nodes below this node. Each single + primitive is supposed to rotate "seperately". That is, you must take into + account the unique center of each one and rotate it around that. If you have + some optimization scheme where you can deal with groups of billboards (ala Performer) + it is valid to do so in the Individual case. */ + bool GetType(int &) const; + /* Center of the thing to be rotated. For Group this does the obvious thing. + For Individual it should be the center of the group of things you want to rotate. + This has no use if you're going to rotate each primitive seperately, but if you've + got some sort of optimized scheme for doing so (ala Performer) this information is useful. + */ + bool GetCenter(trpg3dPoint &) const; + /* The mode will be one of: (1) Axial - rotate around the Axis. This is the normal + one for tree. (2) Eye - Always rotate toward the eye point. (3) world. + */ + bool GetMode(int &) const; + /* The axis used when GetMode returns Axial. */ + bool GetAxis(trpg3dPoint &) const; + + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); +protected: + int type; + int mode; + trpg3dPoint center; + trpg3dPoint axis; +}; + +/* TerraPage level of detail nodes are pretty simple. Even though they don't inherit from trpgGroup, + they have many of the same calls and act, structurally at least, in much the same way. These + act as a switch. When the user's eye point is within a distance then the children of this + node should be turned on for display. Otherwise, the children will be invisible. + + A simple on/off test for a TerraPage lod might look like this: + If ( in < dist < out || out < dist < in) then + Turn children on + else + Turn children off. + + There is also a transition width can be used to fade LODs in and out around + the transition zones. Keep in mind that these LODs are binary. Children + are either on or off (in the process of being turned off). The position of + a child doesn't have any special meaning with respect to range. + + If you're doing a TerraPage reader you'll need to turn this into your own LOD + structure. Keep in mind that trpgAttach nodes can and do attach to trpgLod + nodes. If you have a general purpose LOD in your scene graph this should be + pretty easy. However, you must have implemented the concept of LOD center and + you definitely should *not* recalculate the LOD center yourself based on the + center of child geometry. They may not be the same. In fact, many terrain + LOD schemes depend on them not being the same. + + If you're doing a TerraPage writer you'll need to use these both for geometry + that you want to disappear at certain distances (e.g. trees, houses, etc..), but + also terrain. Any terrain LOD scheme you implement must use these to drop out + polygons in the distance. You'll need to set the center and in/out/width info. + Otherwise it's like a group. + + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgLod : public trpgReadWriteable { +public: + trpgLod(void); + ~trpgLod(void); + // Set the calculated center + void SetCenter(const trpg3dPoint &); + // Set the number of children hint + void SetNumChild(int); + // Set the LOD information + void SetLOD(double in,double out,double width); + + // Center of this LOD. Distance from the viewer is calculated from this. + bool GetCenter(trpg3dPoint &) const; + // Number of children hint. + bool GetNumChild(int &) const; + // LOD specific information. in and out can be switched. width is + // the transition range for doing fading. + bool GetLOD(double &in,double &out,double &width) const; + + // Set the group ID + virtual void SetID(int); + + // Group IDs are used here the same way as in trpgGroup + virtual bool GetID(int &) const; + + // Resets the contents back to empty + void Reset(void); + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); +protected: + int numRange; + double switchIn,switchOut,width; + trpg3dPoint center; + int id; +}; + +/* Layers are used to draw subface geometry. That is, geometry that is + coplanar. This object should be treated just like a group otherwise. + Its existence implies the layering effect. There is no other associated + information. + + If you're doing a TerraPage reader you should assume that each child, + starting at 0 should be draw one after the other using whatever subfacing + scheme you support. There are no restrictions on what the children may + be, but we strongly recommend that writers keep this simple. Keep in + mind that trpgAttach nodes can legally appear as children. If you can pull + it off this has a rather nice effect (think strips on runways). If not, + don't sweat it. + + If you're doing a TerraPage writer, this is fairly simple. Obey the ordering + contraints and try to keep this simple. Ideally that would mean just a few + trpgGeometry nodes below this node. Also keep in mind that layering works + very poorly on most OpenGL systems. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgLayer : public trpgGroup { +public: + trpgLayer(void); + ~trpgLayer(void); + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + // Resets the contents back to empty + void Reset(void); +protected: +}; + +/* This is pretty much a standard 4x4 static transform. It has a matrix + which controls where its children wind up in 3D. Otherwise it acts just + like a trpgGroup. + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgTransform : public trpgGroup { +public: + trpgTransform(void); + ~trpgTransform(void); + + // Set the 4x4 matrix + void SetMatrix(const float64 *); + + // Get the 4x4 matrix + bool GetMatrix(float64 *) const; + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + // Resets the contents back to empty + void Reset(void); +protected: + float64 m[4][4]; +}; + +/* TerraPage treats model references pretty much like instances. Models + are organized centrally in a trpgModelTable. This class simply points + into there with a model ID. There is also a 4x4 matrix (ala trpgTransform) + which moves the model to its final location. + + If you're doing a TerraPage reader you should already have dealt with the + trpgModelTable by this point. Presumably you've got a mapping from model IDs + to small scene graphs in your own representation. This can be treated just like + an instance into one of those. + + If you're doing a TerraPage writer this is pretty simple. When you encounter + a model (external reference) add it to your trpgModelTable and stuff the resulting + model ID into one of these. Stick that trpgModelRef into your tile data stream. + You'll need to fill out the matrix to scale/translate/rotate it as well. + The model is assumed to be spatially within the tile it's written into. That isn't + enforced, though. + + {group:Read/Write Classes} + */ +TX_EXDECL class TX_CLDECL trpgModelRef : public trpgReadWriteable { +public: + trpgModelRef(void); + ~trpgModelRef(void); + // Set the model ID. Must come from a trpgModelTable + void SetModel(int); + // Set the 4x4 rotate/translate/scale matrix + void SetMatrix(const float64 *); + + // Model ID pointing into a trpgModelTable + bool GetModel(int32 &) const; + // Positional matrix. Works just like a trpgTransform. + bool GetMatrix(float64 *) const; + + // Writes this class to a write buffer + bool Write(trpgWriteBuffer &); + // Reads this class from a read buffer + bool Read(trpgReadBuffer &); + // Resets the contents back to empty + void Reset(void); +protected: + int modelRef; + float64 m[4][4]; +}; + +#endif diff --git a/src/osgPlugins/txp/trpage_header.cpp b/src/osgPlugins/txp/trpage_header.cpp new file mode 100644 index 000000000..b2f927390 --- /dev/null +++ b/src/osgPlugins/txp/trpage_header.cpp @@ -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 +#include +#include + +/* 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) + return; + + lodRanges[no] = r; +} +void trpgHeader::SetLodRange(const float64 *r) +{ + for (int i=0;i= 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 (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 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 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 diff --git a/src/osgPlugins/txp/trpage_main.cpp b/src/osgPlugins/txp/trpage_main.cpp new file mode 100644 index 000000000..dbbec0db0 --- /dev/null +++ b/src/osgPlugins/txp/trpage_main.cpp @@ -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 +#endif + +#include +#include + +#include "trdll.h" + +TXDUMMY_DLL_MAIN diff --git a/src/osgPlugins/txp/trpage_material.cpp b/src/osgPlugins/txp/trpage_material.cpp new file mode 100644 index 000000000..150777d18 --- /dev/null +++ b/src/osgPlugins/txp/trpage_material.cpp @@ -0,0 +1,1184 @@ +/* ************************ + 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 +#include +#include + +/* trpage_material.cpp + This source file contains the methods for trpgMatTable, trpgTextureEnv, + trpgMaterial, and trpgTexTable. + You should only modify this code if you want to add data to these classes. + */ + +#include "trpage_geom.h" +#include "trpage_read.h" + +/* Write Material Table class + Keeps track of the materials that have been added. + */ + +// Constructor +trpgMatTable::trpgMatTable() +{ + numTable = numMat = 0; +} +trpgMatTable::~trpgMatTable() +{ +} + +// Reset function +void trpgMatTable::Reset() +{ + numTable = 0; + numMat = 0; + baseMats.resize(0); + matTables.resize(0); +} + +// Validity check +bool trpgMatTable::isValid() const +{ + if (numTable <= 0 || numMat <= 0) + return false; + + for (unsigned int i=0;i= numTable) + return; + if (nm < 0 || nm >= numMat) + return; +#ifdef FIX + tables[nt*numMat+nm] = mat; +#endif +} +void trpgMatTable::SetMaterial(int nm,const trpgMaterial &mat) +{ + if (nm < 0 || nm >= numMat) + return; + +#ifdef FIX + for (int i=0;i= baseMats.size()) + baseMats.push_back(cmat); + + // Add a short material + trpgShortMaterial smat; + smat.baseMat = baseMat; + smat.texids = mat.texids; + matTables.push_back(smat); + + numMat++; + + return numMat-1; +} + +// Write out material table +bool trpgMatTable::Write(trpgWriteBuffer &buf) +{ + int i,j; + + if (!isValid()) + return false; + + buf.Begin(TRPGMATTABLE2); + + // Total number of materials + buf.Add((int32)numTable); + buf.Add((int32)numMat); + + // Dump the short table in first + // These are small materials. They reference the base materials + buf.Begin(TRPGSHORTMATTABLE); + for (i=0;i= numTable || nm < 0 || nm >= numMat) + return false; + const trpgShortMaterial *smat = &matTables[nt*numMat+nm]; + mat = baseMats[smat->baseMat]; + // Now do the overrides for the short material + mat.texids = smat->texids; + + return true; +} +trpgMaterial *trpgMatTable::GetMaterialRef(int nt,int nm) +{ + if (nt < 0 || nt >= numTable || nm < 0 || nm >= numMat) + return 0; + GetMaterial(nt,nm,matRef); + return &matRef; +} + +// This parses both MATTABLE and MATTABLE2 +bool trpgMatTable::Read(trpgReadBuffer &buf) +{ + trpgMaterial mat; + trpgToken matTok; + int32 len; + bool status; + int i,j,k; + + try { + buf.Get(numTable); + buf.Get(numMat); + if (numTable <= 0 || numMat < 0) throw 1; + + // Short material tables are always full size + matTables.resize(numTable*numMat); + + // Look for short material table + buf.GetToken(matTok,len); + if (matTok == TRPGSHORTMATTABLE) { + int32 numTex,texId; + buf.PushLimit(len); + for (i=0;iSetEnvMode(envMode); + break; + case TRPGMAT_TXENV_FILTER: + buf.Get(minFilter); + buf.Get(magFilter); + tenv->SetMinFilter(minFilter); + tenv->SetMagFilter(magFilter); + break; + case TRPGMAT_TXENV_WRAP: + buf.Get(wrapS); + buf.Get(wrapT); + tenv->SetWrap(wrapS,wrapT); + break; + case TRPGMAT_TXENV_BORDER: + buf.Get(borderCol); + tenv->SetBorderColor(borderCol); + break; + default: + // Don't know this token. Skip + break; + } + } + catch (...) { + return NULL; + } + + return tenv; +} + +bool trpgTextureEnv::Read(trpgReadBuffer &buf) +{ + trpgr_Parser parse; + textureEnvCB teCb; + + // Texture environment is a bunch of tokens in random order + // Interface to it with a parser + teCb.tenv = this; + parse.AddCallback(TRPGMAT_TXENV_MODE,&teCb,false); + parse.AddCallback(TRPGMAT_TXENV_FILTER,&teCb,false); + parse.AddCallback(TRPGMAT_TXENV_WRAP,&teCb,false); + parse.AddCallback(TRPGMAT_TXENV_BORDER,&teCb,false); + parse.Parse(buf); + + return isValid(); +} + +/* Write Material class + Material representation. + */ + +// Constructor +trpgMaterial::trpgMaterial() +{ + Reset(); +} +trpgMaterial::~trpgMaterial() +{ +} + +// Reset function +void trpgMaterial::Reset() +{ + color = trpgColor(1,1,1); + ambient = trpgColor(0,0,0); + diffuse = trpgColor(1,1,1); + specular = trpgColor(0,0,0); + emission = trpgColor(0,0,0); + shininess = 0; + shadeModel = Smooth; + pointSize = 1; + lineWidth = 1; + cullMode = Back; + alphaFunc = GreaterThan; + alphaRef = 0; + alpha = 1.0; + autoNormal = false; + numTex = 0; + texids.resize(0); + texEnvs.resize(0); + numTile = 0; +} + +// Validity check +bool trpgMaterial::isValid() const +{ + // Only thing we really care about is texture + if (numTex < 0) + return false; + + for (int i=0;i= texids.size()) + return; + + texids[no] = id; + texEnvs[no] = env; +} +int trpgMaterial::AddTexture(int id,const trpgTextureEnv &env) +{ + texids.push_back(id); + texEnvs.push_back(env); + numTex++; + + return numTex-1; +} +void trpgMaterial::SetNumTiles(int no) +{ + numTile = no; +} +int trpgMaterial::AddTile() +{ + return(++numTile); +} + +// Write to buffer +bool trpgMaterial::Write(trpgWriteBuffer &buf) +{ + if (!isValid()) + return false; + + buf.Begin(TRPGMATERIAL); + + // Bundle the basic material parameters together + buf.Begin(TRPGMAT_BASIC); + buf.Add(color); + buf.Add(ambient); + buf.Add(diffuse); + buf.Add(specular); + buf.Add(emission); + buf.Add(shininess); + buf.Add(numTile); + buf.End(); + + // Most everything else is a single token. + // This is inefficient, but expandable + buf.Begin(TRPGMAT_SHADE); + buf.Add(shadeModel); + buf.End(); + + buf.Begin(TRPGMAT_SIZES); + buf.Add(pointSize); + buf.Add(lineWidth); + buf.End(); + + buf.Begin(TRPGMAT_CULL); + buf.Add(cullMode); + buf.End(); + + buf.Begin(TRPGMAT_ALPHA); + buf.Add(alphaFunc); + buf.Add(alphaRef); + buf.Add(alpha); + buf.End(); + + buf.Begin(TRPGMAT_NORMAL); + buf.Add(autoNormal); + buf.End(); + + buf.Begin(TRPGMAT_TEXTURE); + buf.Add(numTex); + for (int i=0;i= numTex) + return false; + id = texids[no]; + te = texEnvs[no]; + return true; +} +bool trpgMaterial::GetNumTile(int &no) const +{ + if (!isValid()) return false; + no = numTile; + return true; +} + +/* Material CB + Used to parse tokens for a material. + */ +class materialCB : public trpgr_Callback { +public: + void * Parse(trpgToken,trpgReadBuffer &); + trpgMaterial *mat; +}; +void * materialCB::Parse(trpgToken tok,trpgReadBuffer &buf) +{ + trpgColor color; + float64 shininess; + int shadeModel; + float64 size; + int cullMode; + int alphaFunc; + float64 alphaRef,alpha; + bool autoNormal; + int numTex,texId; + trpgToken envTok; + trpgTextureEnv texEnv; + int32 len,numtile; + bool status; + int i; + + try { + switch (tok) { + case TRPGMAT_BASIC: + buf.Get(color); + mat->SetColor(color); + buf.Get(color); + mat->SetAmbient(color); + buf.Get(color); + mat->SetDiffuse(color); + buf.Get(color); + mat->SetSpecular(color); + buf.Get(color); + mat->SetEmission(color); + buf.Get(shininess); + mat->SetShininess(shininess); + buf.Get(numtile); + mat->SetNumTiles(numtile); + break; + case TRPGMAT_SHADE: + buf.Get(shadeModel); + mat->SetShadeModel(shadeModel); + break; + case TRPGMAT_SIZES: + buf.Get(size); + mat->SetPointSize(size); + buf.Get(size); + mat->SetLineWidth(size); + break; + case TRPGMAT_CULL: + buf.Get(cullMode); + mat->SetCullMode(cullMode); + break; + case TRPGMAT_ALPHA: + buf.Get(alphaFunc); + buf.Get(alphaRef); + buf.Get(alpha); + mat->SetAlphaFunc(alphaFunc); + mat->SetAlphaRef(alphaRef); + mat->SetAlpha(alpha); + break; + case TRPGMAT_NORMAL: + { + int tmp; + buf.Get(tmp); + if (tmp) + autoNormal = true; + else + autoNormal = false; + mat->SetAutoNormal(autoNormal); + } + break; + case TRPGMAT_TEXTURE: + buf.Get(numTex); + for (i=0;iAddTexture(texId,texEnv); + } + break; + default: + break; + } + } + catch (...) { + return NULL; + } + + return mat; +} + +bool trpgMaterial::Read(trpgReadBuffer &buf) +{ + trpgr_Parser parse; + materialCB matCb; + + // Material is just a bunch of unordered tokens. + // Interface to it with a generic parser + matCb.mat = this; + parse.AddCallback(TRPGMAT_BASIC,&matCb,false); + parse.AddCallback(TRPGMAT_SHADE,&matCb,false); + parse.AddCallback(TRPGMAT_SIZES,&matCb,false); + parse.AddCallback(TRPGMAT_CULL,&matCb,false); + parse.AddCallback(TRPGMAT_ALPHA,&matCb,false); + parse.AddCallback(TRPGMAT_NORMAL,&matCb,false); + parse.AddCallback(TRPGMAT_TEXTURE,&matCb,false); + parse.Parse(buf); + + return isValid(); +} + +/* Texture + Really just a container for a texture name and use count. + The use count is used for paging. + */ + +// Constructor +trpgTexture::trpgTexture() +{ + name = NULL; + useCount = 0; +} + +// Copy construction +trpgTexture::trpgTexture(const trpgTexture &in) +{ + name = NULL; + useCount = 0; + *this = in; +} + +// Destruction +trpgTexture::~trpgTexture() +{ + Reset(); +} + +// Reset +void trpgTexture::Reset() +{ + if (name) + delete name; + name = NULL; + useCount = 0; +} + +// Valid if we've got a name +bool trpgTexture::isValid() const +{ + if (name) + return true; + + return false; +} + +// Set Name +void trpgTexture::SetName(const char *inName) +{ + if (name) + delete name; + if (!inName || strlen(inName) < 1) + return; + + name = new char[strlen(inName)+1]; + strcpy(name,inName); +} + +// Get Name +bool trpgTexture::GetName(char *outName,int outLen) const +{ + if (!isValid()) return false; + + int len = (name) ? strlen(name) : 0; + strncpy(outName,name,MIN(len,outLen)+1); + + return true; +} + +// Use count management +void trpgTexture::SetNumTile(int num) +{ + useCount = num; +} +void trpgTexture::AddTile() +{ + useCount++; +} +bool trpgTexture::GetNumTile(int &num) const +{ + if (!isValid()) return false; + num = useCount; + return true; +} + +// Copy operator +trpgTexture &trpgTexture::operator = (const trpgTexture &in) +{ + SetName(in.name); + useCount = in.useCount; + + return *this; +} + +// Equality operator +int trpgTexture::operator == (const trpgTexture &in) const +{ + if (!in.name && !name) + return 1; + if (!in.name || !name) + return 0; + return (!strcmp(in.name,name)); +} + +// Write function +bool trpgTexture::Write(trpgWriteBuffer &buf) +{ + if (!isValid()) return false; + + buf.Add(name); + buf.Add(useCount); + + return true; +} + +// Read function +bool trpgTexture::Read(trpgReadBuffer &buf) +{ + char texName[1024]; + + try { + buf.Get(texName,1023); + SetName(texName); + buf.Get(useCount); + } + catch (...) { + return false; + } + + if (!isValid()) return false; + return true; +} + +/* Texture Table + Just a list of texture names so we can index. + */ + +// Constructor +trpgTexTable::trpgTexTable() +{ +} +trpgTexTable::trpgTexTable(const trpgTexTable &in) +{ + *this = in; +} + +// Reset function +void trpgTexTable::Reset() +{ + texList.resize(0); +} + +// Destructor +trpgTexTable::~trpgTexTable() +{ + Reset(); +} + +// Validity check +bool trpgTexTable::isValid() const +{ + for (unsigned int i=0;i= (int)texList.size()) + return; + + texList[id] = inTex; +} + +// Copy operator +trpgTexTable &trpgTexTable::operator = (const trpgTexTable &in) +{ + for (unsigned int i=0;i= (int)texList.size()) return false; + + ret = texList[id]; + return true; +} +trpgTexture *trpgTexTable::GetTextureRef(int id) +{ + if (id < 0 || id >= (int)texList.size()) return NULL; + return &texList[id]; +} + +bool trpgTexTable::Read(trpgReadBuffer &buf) +{ + int32 numTex; + trpgTexture tex; + + try { + buf.Get(numTex); + for (int i=0;i +#include +#include + +/* 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()) + 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 +#include +#include + +/* 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; +} diff --git a/src/osgPlugins/txp/trpage_parse.cpp b/src/osgPlugins/txp/trpage_parse.cpp new file mode 100644 index 000000000..ac7d96984 --- /dev/null +++ b/src/osgPlugins/txp/trpage_parse.cpp @@ -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 +#include + +/* 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() +{ +}; diff --git a/src/osgPlugins/txp/trpage_rarchive.cpp b/src/osgPlugins/txp/trpage_rarchive.cpp new file mode 100644 index 000000000..48340ad41 --- /dev/null +++ b/src/osgPlugins/txp/trpage_rarchive.cpp @@ -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 +#include +#include + +/* 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; +} diff --git a/src/osgPlugins/txp/trpage_read.h b/src/osgPlugins/txp/trpage_read.h new file mode 100644 index 000000000..e31c8516a --- /dev/null +++ b/src/osgPlugins/txp/trpage_read.h @@ -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 tok_map; +#else + typedef map > 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 parents; +}; + +#endif diff --git a/src/osgPlugins/txp/trpage_readbuf.cpp b/src/osgPlugins/txp/trpage_readbuf.cpp new file mode 100644 index 000000000..4a5fad8f8 --- /dev/null +++ b/src/osgPlugins/txp/trpage_readbuf.cpp @@ -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 +#include +#include +#include + +/* 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 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[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= len) + return true; + + // Also test the limits + for (unsigned int i=0;i 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; +} diff --git a/src/osgPlugins/txp/trpage_scene.cpp b/src/osgPlugins/txp/trpage_scene.cpp new file mode 100644 index 000000000..1281fa778 --- /dev/null +++ b/src/osgPlugins/txp/trpage_scene.cpp @@ -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 +#include +#include + +/* 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 +#include + +/* **************** + 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= (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(&mbr); + trpgMBR kmbr; + // Ask the kids + for (unsigned int i=0;iGetMBR(); + cmbr->Union(kmbr); + } + return *cmbr; + } +} + +/* **************** + Read Geometry + **************** + */ +// Calculate an MBR +trpgMBR trpgReadGeometry::GetMBR() const +{ + if (mbr.isValid()) + return mbr; + + trpgMBR *pmbr = const_cast(&mbr); + + int numVert,i; + trpg3dPoint pt; + data.GetNumVertex(numVert); + numVert /= 3; + for (i=0;iAddPoint(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; +} diff --git a/src/osgPlugins/txp/trpage_scene.h b/src/osgPlugins/txp/trpage_scene.h new file mode 100644 index 000000000..e5a6c891d --- /dev/null +++ b/src/osgPlugins/txp/trpage_scene.h @@ -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 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 GroupMap; +#else + typedef map > 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 diff --git a/src/osgPlugins/txp/trpage_swap.cpp b/src/osgPlugins/txp/trpage_swap.cpp new file mode 100644 index 000000000..dd541bf1a --- /dev/null +++ b/src/osgPlugins/txp/trpage_swap.cpp @@ -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 +#include + +/* 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; +} + diff --git a/src/osgPlugins/txp/trpage_swap.h b/src/osgPlugins/txp/trpage_swap.h new file mode 100644 index 000000000..1e2dd4f28 --- /dev/null +++ b/src/osgPlugins/txp/trpage_swap.h @@ -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 diff --git a/src/osgPlugins/txp/trpage_sys.h b/src/osgPlugins/txp/trpage_sys.h new file mode 100644 index 000000000..0c2c9c62a --- /dev/null +++ b/src/osgPlugins/txp/trpage_sys.h @@ -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 + +// 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 + +// Delete a file +#define TRPGDELETEFILE(file) remove((file)) + +//#ifndef int64 +//typedef long long int64; +//#endif + +#if defined(sgi) && defined(unix) +# include +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 +typedef longlong_t int64; + +#elif defined(sun) && defined(unix) +// This should work on SunOS 5.7 and later. +#include +typedef int64_t int64; + +#elif defined(linux) +#include +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 +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(vxw) || (defined(sgi) && defined(_STANDARD_C_PLUS_PLUS)) || (defined(__GNUC__) && (__GNUC__>=2) && (__GNUC_MINOR__>=91)) +#include +#include +namespace std {} +using namespace std; +#else +#include +#include +#endif + +//#if defined(_WIN32) +//#include +//#include +//#else +//#include +//#include +//#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 diff --git a/src/osgPlugins/txp/trpage_tile.cpp b/src/osgPlugins/txp/trpage_tile.cpp new file mode 100644 index 000000000..4fc5dca69 --- /dev/null +++ b/src/osgPlugins/txp/trpage_tile.cpp @@ -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 +#include +#include + +/* 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= 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= (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= (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;iAddMaterial(id); + } + break; + case TRPG_TILE_MODELLIST: + buf.Get(no); + if (no < 0) throw 1; + for (i=0;iAddModel(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(); +} diff --git a/src/osgPlugins/txp/trpage_warchive.cpp b/src/osgPlugins/txp/trpage_warchive.cpp new file mode 100644 index 000000000..30f49f7ca --- /dev/null +++ b/src/osgPlugins/txp/trpage_warchive.cpp @@ -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 +#include +#include + +/* 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 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;iGetEndian() != 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 tex; + vector norm,vert; + // Data arrays for a polygon + int32 matPoly; + vector polyTex; + vector 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 diff --git a/src/osgPlugins/txp/trpage_writebuf.cpp b/src/osgPlugins/txp/trpage_writebuf.cpp new file mode 100644 index 000000000..6f6e46b14 --- /dev/null +++ b/src/osgPlugins/txp/trpage_writebuf.cpp @@ -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 +#include +#include + +/* 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); +} diff --git a/src/osgText/Paragraph.cpp b/src/osgText/Paragraph.cpp index ac6047b8a..05f7ede4d 100644 --- a/src/osgText/Paragraph.cpp +++ b/src/osgText/Paragraph.cpp @@ -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(copyop(paragraph._font.get()))),