aboutsummaryrefslogtreecommitdiff
path: root/tool_src/BspLib
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
committerFelix Morgner <felix.morgner@gmail.com>2026-08-24 11:16:07 +0200
commitc068f22329d5cc722622a2183bbb22eef2093df7 (patch)
tree12d56c1aede67988a55e241364606bfbb4dba933 /tool_src/BspLib
downloadopenparsec-main.tar.xz
openparsec-main.zip
initial importHEADmain
Diffstat (limited to 'tool_src/BspLib')
-rw-r--r--tool_src/BspLib/AodFormat.cpp39
-rw-r--r--tool_src/BspLib/AodFormat.h59
-rw-r--r--tool_src/BspLib/AodInput.cpp183
-rw-r--r--tool_src/BspLib/AodInput.h42
-rw-r--r--tool_src/BspLib/AodOutput.cpp106
-rw-r--r--tool_src/BspLib/AodOutput.h41
-rw-r--r--tool_src/BspLib/BRep.cpp1514
-rw-r--r--tool_src/BspLib/BRep.h93
-rw-r--r--tool_src/BspLib/BSPNode.cpp401
-rw-r--r--tool_src/BspLib/BSPNode.h132
-rw-r--r--tool_src/BspLib/BSPTree.cpp121
-rw-r--r--tool_src/BspLib/BSPTree.h182
-rw-r--r--tool_src/BspLib/BoundingBox.cpp223
-rw-r--r--tool_src/BspLib/BoundingBox.h72
-rw-r--r--tool_src/BspLib/BspFormat.cpp71
-rw-r--r--tool_src/BspLib/BspFormat.h77
-rw-r--r--tool_src/BspLib/BspInput.cpp406
-rw-r--r--tool_src/BspLib/BspInput.h48
-rwxr-xr-xtool_src/BspLib/BspLib.vcproj1055
-rwxr-xr-xtool_src/BspLib/BspLib.vcxproj385
-rwxr-xr-xtool_src/BspLib/BspLib.vcxproj.filters272
-rwxr-xr-xtool_src/BspLib/BspLib.vcxproj.user4
-rw-r--r--tool_src/BspLib/BspLibDefs.h163
-rw-r--r--tool_src/BspLib/BspObject.cpp641
-rw-r--r--tool_src/BspLib/BspObject.h258
-rw-r--r--tool_src/BspLib/BspObjectList.cpp197
-rw-r--r--tool_src/BspLib/BspObjectList.h151
-rw-r--r--tool_src/BspLib/BspOutput.cpp108
-rw-r--r--tool_src/BspLib/BspOutput.h41
-rw-r--r--tool_src/BspLib/BspTool.cpp68
-rw-r--r--tool_src/BspLib/BspTool.h34
-rw-r--r--tool_src/BspLib/COPYING482
-rw-r--r--tool_src/BspLib/Chunk.h280
-rw-r--r--tool_src/BspLib/EpsAreas.cpp28
-rw-r--r--tool_src/BspLib/Face.cpp352
-rw-r--r--tool_src/BspLib/Face.h223
-rw-r--r--tool_src/BspLib/IOData3D.cpp45
-rw-r--r--tool_src/BspLib/IOData3D.h76
-rw-r--r--tool_src/BspLib/InputData3D.cpp175
-rw-r--r--tool_src/BspLib/InputData3D.h83
-rw-r--r--tool_src/BspLib/LineSeg.cpp71
-rw-r--r--tool_src/BspLib/LineSeg2.h46
-rw-r--r--tool_src/BspLib/LineSeg3.h46
-rw-r--r--tool_src/BspLib/Makefile62
-rw-r--r--tool_src/BspLib/Mapping.cpp63
-rw-r--r--tool_src/BspLib/Mapping.h89
-rw-r--r--tool_src/BspLib/Material.h57
-rw-r--r--tool_src/BspLib/ObjectAodFormat.cpp200
-rw-r--r--tool_src/BspLib/ObjectAodFormat.h52
-rw-r--r--tool_src/BspLib/ObjectBSPNode.cpp170
-rw-r--r--tool_src/BspLib/ObjectBSPNode.h70
-rw-r--r--tool_src/BspLib/ObjectBSPTree.h97
-rw-r--r--tool_src/BspLib/ObjectBinFormat.cpp758
-rw-r--r--tool_src/BspLib/ObjectBinFormat.h55
-rw-r--r--tool_src/BspLib/ObjectBspFormat.cpp213
-rw-r--r--tool_src/BspLib/ObjectBspFormat.h53
-rw-r--r--tool_src/BspLib/OutputData3D.cpp105
-rw-r--r--tool_src/BspLib/OutputData3D.h44
-rw-r--r--tool_src/BspLib/Plane.h146
-rw-r--r--tool_src/BspLib/Polygon.cpp1042
-rw-r--r--tool_src/BspLib/Polygon.h280
-rw-r--r--tool_src/BspLib/PolygonList.cpp213
-rw-r--r--tool_src/BspLib/PolygonList.h153
-rw-r--r--tool_src/BspLib/SingleFormat.cpp158
-rw-r--r--tool_src/BspLib/SingleFormat.h119
-rw-r--r--tool_src/BspLib/SingleInput.cpp699
-rw-r--r--tool_src/BspLib/SingleInput.h83
-rw-r--r--tool_src/BspLib/SingleOutput.cpp125
-rw-r--r--tool_src/BspLib/SingleOutput.h44
-rw-r--r--tool_src/BspLib/SystemIO.cpp314
-rw-r--r--tool_src/BspLib/SystemIO.h172
-rw-r--r--tool_src/BspLib/Texture.cpp77
-rw-r--r--tool_src/BspLib/Texture.h58
-rw-r--r--tool_src/BspLib/Transform2.cpp282
-rw-r--r--tool_src/BspLib/Transform2.h111
-rw-r--r--tool_src/BspLib/Transform3.cpp312
-rw-r--r--tool_src/BspLib/Transform3.h106
-rw-r--r--tool_src/BspLib/TriMapping.cpp26
-rw-r--r--tool_src/BspLib/TriMapping.h43
-rw-r--r--tool_src/BspLib/Vector.h100
-rw-r--r--tool_src/BspLib/Vector2.h113
-rw-r--r--tool_src/BspLib/Vector3.h134
-rw-r--r--tool_src/BspLib/Vertex.cpp47
-rw-r--r--tool_src/BspLib/Vertex.h206
-rw-r--r--tool_src/BspLib/Vertex2.h76
-rw-r--r--tool_src/BspLib/Vertex3.h72
-rw-r--r--tool_src/BspLib/VertexChunk.cpp237
-rw-r--r--tool_src/BspLib/VertexChunk.h129
-rw-r--r--tool_src/BspLib/VrmlFile.cpp133
-rw-r--r--tool_src/BspLib/VrmlFile.h48
90 files changed, 17040 insertions, 0 deletions
diff --git a/tool_src/BspLib/AodFormat.cpp b/tool_src/BspLib/AodFormat.cpp
new file mode 100644
index 0000000..8ee949c
--- /dev/null
+++ b/tool_src/BspLib/AodFormat.cpp
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: AodFormat.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "AodFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// get index to section id specified as string (this function is static!) -----
+//
+int AodFormat::GetSectionId( char *section_name )
+{
+ return SingleFormat::GetSectionId( section_name );
+}
+
+
+// get name of section specified via id (this function is static!) ------------
+//
+const char *AodFormat::GetSectionName( int section_id )
+{
+ return SingleFormat::GetSectionName( section_id );
+}
+
+
+// AodFormat specific static variables ----------------------------------------
+//
+const char AodFormat::_aodsig_str[] = "#AOD";
+const char AodFormat::AOD_FILE_EXTENSION[] = ".aod";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/AodFormat.h b/tool_src/BspLib/AodFormat.h
new file mode 100644
index 0000000..64a216c
--- /dev/null
+++ b/tool_src/BspLib/AodFormat.h
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: AodFormat.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _AODFORMAT_H_
+#define _AODFORMAT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SingleFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class containing aod format specifics --------------------------------------
+//
+class AodFormat : public virtual SingleFormat {
+
+protected:
+
+ // section enumeration
+ enum {
+ _num_aod_sections = _num_single_sections
+ };
+
+//protected:
+public:
+ AodFormat() { }
+ ~AodFormat() { }
+
+ AodFormat( const AodFormat& copyobj ) : SingleFormat( copyobj ) { }
+ AodFormat& operator =( const AodFormat& copyobj );
+
+protected:
+ static int GetSectionId( char *section_name );
+ static const char* GetSectionName( int section_id );
+
+protected:
+ static const char _aodsig_str[];
+ static const char AOD_FILE_EXTENSION[];
+};
+
+// assignment operator --------------------------------------------------------
+inline AodFormat& AodFormat::operator =( const AodFormat& copyobj )
+{
+ *(SingleFormat *)this = copyobj;
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _AODFORMAT_H_
+
diff --git a/tool_src/BspLib/AodInput.cpp b/tool_src/BspLib/AodInput.cpp
new file mode 100644
index 0000000..1224a9e
--- /dev/null
+++ b/tool_src/BspLib/AodInput.cpp
@@ -0,0 +1,183 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: AodInput.cpp
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "AodInput.h"
+#include "BspObject.h"
+#include "BspTool.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file is read and parsed immediately after construction of an object --------
+//
+AodInput::AodInput( BspObjectList objectlist, const char *filename ) :
+ SingleInput( objectlist, filename )
+{
+ ParseObjectData();
+}
+
+
+// destructor destroys only class members and the base classes ----------------
+//
+AodInput::~AodInput()
+{
+}
+
+
+// assignment copies only the AodFormat part of the object --------------------
+//
+AodInput& AodInput::operator =( const AodInput& copyobj )
+{
+ *(AodFormat *)this = copyobj;
+ return *this;
+}
+
+
+// print error message if error in object data-file ---------------------------
+//
+void AodInput::ParseError( int section )
+{
+ //NOTE:
+ // GetSectionName() is overloaded and not virtual, therefore
+ // SingleInput's ParseError() cannot be used!
+ sprintf( line, "%sin section %s (line %d)", parser_err_str,
+ GetSectionName( section ), m_parser_lineno );
+ ErrorMessage( line );
+ HandleCriticalError();
+}
+
+
+// parse object data-file -----------------------------------------------------
+//
+int AodInput::ParseObjectData()
+{
+ int faceprop_itemsread = 0;
+ int facenorm_itemsread = 0;
+
+ InfoMessage( "Processing input data file (format='AOD V1.1') ..." );
+
+ // parse sections and read data -------------------------------
+ m_section = _nil;
+ while ( m_input.ReadLine( line, TEXTLINE_MAX ) != NULL ) {
+
+ if ( ( m_parser_lineno++ & PARSER_DOT_SIZE ) == 0 )
+ printf( "." ), fflush( stdout );
+
+ if ( ( m_scanptr = strtok( line, "/, \t\n\r" ) ) == NULL )
+ continue;
+ else if ( *m_scanptr == ';' )
+ continue;
+ else if ( strnicmp( m_scanptr, "<end", 4 ) == 0 )
+ break;
+ else if ( *m_scanptr == '#' ) {
+ if ( strncmp( m_scanptr, _aodsig_str, strlen( _aodsig_str ) ) == 0 ) {
+ m_section = _comment;
+ } else if ( ( m_section = GetSectionId( m_scanptr ) ) == _nil ) {
+ {
+ StrScratch error;
+ sprintf( error, "%s[Undefined section-name]: %s (line %d)",
+ parser_err_str, m_scanptr, m_parser_lineno );
+ ErrorMessage( error );
+ }
+ HandleCriticalError();
+ }
+ } else {
+ switch ( m_section ) {
+
+ // list of vertices ------------------------------------
+ case _vertices :
+ ReadVertex();
+ break;
+
+ // vertexnums of faces ---------------------------------
+ case _faces :
+ ReadFace( TRUE );
+ break;
+
+ // normals for face's planes ---------------------------
+ case _facenormals :
+
+ //NOTE:
+ // face normals are currently ignored in the aod
+ // file, since they are too inaccurate for later
+ // BSP compilation purposes. if no normals are read
+ // in, they will be calculated later on anyway.
+
+ //ReadFaceNormal( facenorm_itemsread );
+ break;
+
+ // properties of faces ---------------------------------
+ case _faceproperties :
+ ReadFaceProperties( faceprop_itemsread );
+ break;
+
+ // texture->face correspondences ----------------------
+ case _correspondences :
+ ReadCorrespondences();
+ break;
+
+ // texturing data -----------------------------------
+ case _textures :
+ ReadTextures();
+ break;
+
+ // location of the object ---------------------------
+ case _worldlocation :
+ ReadWorldLocation();
+ break;
+
+ // location of camera -------------------------------
+ case _camera :
+ ReadCameraLocation();
+ break;
+
+ // filename of palette file -------------------------
+ case _palette :
+ ReadPaletteFilename();
+ break;
+
+ // scalefactors for object --------------------------
+ case _scalefactors :
+ ReadScaleFactors();
+ break;
+
+ // exchange command for axes ------------------------
+ case _xchange :
+ ReadXChangeCommand();
+ break;
+
+ // set new object origin ----------------------------
+ case _setorigin :
+ ReadOrigin();
+ break;
+
+ }
+ }
+ }
+
+ // do post processing after parsing
+ ApplyOriginTranslation();
+ FilterAxesDirSwitch();
+ FilterScaleFactors();
+ FilterAxesExchange();
+ EnforceMaximumExtents();
+ m_baseobject->CheckParsedData();
+
+ InfoMessage( "\nObject data ok.\n" );
+
+ // do colorindex to rgb conversion
+ ConvertColIndxs();
+
+ return ( m_inputok = TRUE );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/AodInput.h b/tool_src/BspLib/AodInput.h
new file mode 100644
index 0000000..e04b13f
--- /dev/null
+++ b/tool_src/BspLib/AodInput.h
@@ -0,0 +1,42 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: AodInput.h
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _AODINPUT_H_
+#define _AODINPUT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "AodFormat.h"
+#include "SingleInput.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file input class for aod format files --------------------------------------
+//
+class AodInput : public AodFormat, public SingleInput {
+
+public:
+ AodInput( BspObjectList objectlist, const char *filename );
+ ~AodInput();
+
+ AodInput& operator =( const AodInput& copyobj );
+
+public:
+ int ParseObjectData();
+
+protected:
+ void ParseError( int section );
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _AODINPUT_H_
+
diff --git a/tool_src/BspLib/AodOutput.cpp b/tool_src/BspLib/AodOutput.cpp
new file mode 100644
index 0000000..316cf9a
--- /dev/null
+++ b/tool_src/BspLib/AodOutput.cpp
@@ -0,0 +1,106 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: AodOutput.cpp
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "AodOutput.h"
+#include "BspObject.h"
+#include "BspTool.h"
+#include "ObjectAodFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct AodOutput object -------------------------------------------------
+//
+AodOutput::AodOutput( BspObjectList objectlist, const char *filename ) :
+ SingleOutput( objectlist, BspTool::ChangeExtension( filename, AOD_FILE_EXTENSION ) )
+{
+}
+
+
+// construct AodOutput object using an InputData3D object ---------------------
+//
+AodOutput::AodOutput( const InputData3D& inputdata ) :
+ SingleOutput( inputdata.getObjectList(),
+ BspTool::ChangeExtension( inputdata.getFileName(), AOD_FILE_EXTENSION ) )
+{
+ // get pointer to "real" input object
+ InputData3D *inputobj = inputdata.getRealObject();
+
+ // try to isolate the AodFormat part of the input object
+ AodFormat *aodformat = dynamic_cast<AodFormat*>(inputobj);
+
+ // copy over if cast succeeded
+ if ( aodformat != NULL ) {
+
+ *(AodFormat *)this = *aodformat;
+
+ } else {
+
+ // try to isolate the SingleFormat part of the input object
+ SingleFormat *singleformat = dynamic_cast<SingleFormat*>(inputobj);
+
+ // copy over if cast succeeded
+ if ( singleformat != NULL )
+ *(SingleFormat *)this = *singleformat;
+ }
+}
+
+
+// write outputfile before destruction ----------------------------------------
+//
+AodOutput::~AodOutput()
+{
+ if ( m_output.Status() == SYSTEM_IO_OK )
+ WriteOutputFile();
+}
+
+
+// assignment copies only the AodFormat part of the object --------------------
+//
+AodOutput& AodOutput::operator =( const AodOutput& copyobj )
+{
+ *(AodFormat *)this = copyobj;
+ return *this;
+}
+
+
+// write '.aod' file for this object ------------------------------------------
+//
+int AodOutput::WriteOutputFile()
+{
+ sprintf( line, "Writing ascii object data to \"%s\"...\n", (const char *) m_filename );
+ InfoMessage( line );
+
+ sprintf( line, "%s\n\n", AOD_SIGNATURE_1_1 );
+ m_output.WriteLine( line );
+
+ // write bsplib banner to file and init output data
+ SingleOutput::InitOutput();
+
+ // create 3-D object knowing about '.aod' format
+ ObjectAodFormat obj( *m_baseobject, *this );
+
+ // write attribute lists
+ obj.WriteVertexList( m_output );
+ obj.WriteFaceList( m_output );
+ obj.WriteNormals( m_output );
+ obj.WriteFaceProperties( m_output );
+ obj.WriteMappingList( m_output );
+ obj.WriteTextureList( m_output );
+
+ // write common part
+ SingleOutput::WriteOutputFile();
+
+ return m_output.Status();
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/AodOutput.h b/tool_src/BspLib/AodOutput.h
new file mode 100644
index 0000000..88a2f0e
--- /dev/null
+++ b/tool_src/BspLib/AodOutput.h
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: AodOutput.h
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _AODOUTPUT_H_
+#define _AODOUTPUT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "AodFormat.h"
+#include "SingleOutput.h"
+#include "InputData3D.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file output class for aod format files -------------------------------------
+//
+class AodOutput : public AodFormat, public SingleOutput {
+
+public:
+ AodOutput( BspObjectList objectlist, const char *filename );
+ AodOutput( const InputData3D& inputdata );
+ ~AodOutput();
+
+ AodOutput& operator =( const AodOutput& copyobj );
+
+public:
+ int WriteOutputFile();
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _AODOUTPUT_H_
+
diff --git a/tool_src/BspLib/BRep.cpp b/tool_src/BspLib/BRep.cpp
new file mode 100644
index 0000000..1b4a49a
--- /dev/null
+++ b/tool_src/BspLib/BRep.cpp
@@ -0,0 +1,1514 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BRep.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "BRep.h"
+
+// qvlib headers
+#include <QvCoordinate3.h>
+#include <QvMaterial.h>
+#include <QvMaterialBinding.h>
+#include <QvMatrixTransform.h>
+#include <QvNormal.h>
+#include <QvNormalBinding.h>
+#include <QvRotation.h>
+#include <QvScale.h>
+#include <QvShapeHints.h>
+#include <QvTexture2.h>
+#include <QvTextureCoordinate2.h>
+#include <QvTexture2Transform.h>
+#include <QvTranslation.h>
+#include <QvTransform.h>
+
+#ifdef USE_JPEG_LIBRARY
+#include <jpeglib.h>
+#endif
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+struct tga_header_s {
+
+ byte IDLength;
+ byte CMapType;
+ byte ImgType;
+ byte CMapStartLo;
+ byte CMapStartHi;
+ byte CMapLengthLo;
+ byte CMapLengthHi;
+ byte CMapDepth;
+ byte XOffSetLo;
+ byte XOffSetHi;
+ byte YOffSetLo;
+ byte YOffSetHi;
+ byte WidthLo;
+ byte WidthHi;
+ byte HeightLo;
+ byte HeightHi;
+ byte PixelDepth;
+ byte ImageDescriptor;
+};
+
+
+// constructor for b-rep object -----------------------------------------------
+//
+BRep::BRep( QvState *state )
+{
+ // save pointer to state
+ m_state = state;
+
+ // create new object and insert into list
+ m_baseobject = m_state->vrmlfile_base->getObjectList().CreateNewObject();
+}
+
+
+// fetch pointer to Coordinate3 array and length ------------------------------
+//
+float *BRep::FetchCoordinate3State( int &num )
+{
+ num = 0;
+ float *coarray = NULL;
+ QvElement *elt = m_state->getTopElement( QvState::Coordinate3Index );
+
+ if ( elt != NULL ) {
+ QvCoordinate3 *c3 = (QvCoordinate3 *) elt->data;
+ num = c3->point.num;
+ coarray = c3->point.values;
+ }
+
+ return coarray;
+}
+
+
+// fetch pointer to texture coordinates array and length ----------------------
+//
+float *BRep::FetchTextureCoordinate2State( int &num )
+{
+ num = 0;
+ float *coarray = NULL;
+ QvElement *elt = m_state->getTopElement( QvState::TextureCoordinate2Index );
+
+ if ( elt != NULL ) {
+ QvTextureCoordinate2 *tc = (QvTextureCoordinate2 *) elt->data;
+ num = tc->point.num;
+ coarray = tc->point.values;
+ }
+
+ return coarray;
+}
+
+
+// fetch pointer to normals array and length ----------------------------------
+//
+float *BRep::FetchNormalState( int &num )
+{
+ num = 0;
+ float *coarray = NULL;
+ QvElement *elt = m_state->getTopElement( QvState::NormalIndex );
+
+ if ( elt != NULL ) {
+ QvNormal *nml = (QvNormal *) elt->data;
+ num = nml->vector.num;
+ coarray = nml->vector.values;
+ }
+
+ return coarray;
+}
+
+
+// accumulate current transformation stack and init Transform3 object ---------
+//
+void BRep::FetchTransformationState( Transform3& trafo )
+{
+ trafo.LoadIdentity();
+
+ QvElement *trafoelt = NULL;
+ trafoelt = m_state->getTopElement( QvState::TransformationIndex );
+ for ( ; trafoelt; trafoelt = trafoelt->next ) {
+
+ if ( trafoelt->type == QvElement::Translation ) {
+ QvTranslation *tnode = (QvTranslation *) trafoelt->data;
+ trafo.Translate( tnode->translation.value[ 0 ],
+ tnode->translation.value[ 1 ],
+ tnode->translation.value[ 2 ] );
+ } else if ( trafoelt->type == QvElement::Rotation ) {
+ QvRotation *tnode = (QvRotation *) trafoelt->data;
+ trafo.Rotate( tnode->rotation.angle,
+ tnode->rotation.axis[ 0 ],
+ tnode->rotation.axis[ 1 ],
+ tnode->rotation.axis[ 2 ] );
+ } else if ( trafoelt->type == QvElement::Scale ) {
+ QvScale *tnode = (QvScale *) trafoelt->data;
+ trafo.Scale( tnode->scaleFactor.value[ 0 ],
+ tnode->scaleFactor.value[ 1 ],
+ tnode->scaleFactor.value[ 2 ] );
+ } else if ( trafoelt->type == QvElement::Transform ) {
+ QvTransform *tnode = (QvTransform *) trafoelt->data;
+ trafo.Translate( -tnode->center.value[ 0 ],
+ -tnode->center.value[ 1 ],
+ -tnode->center.value[ 2 ] );
+ trafo.Rotate( -tnode->scaleOrientation.angle,
+ tnode->scaleOrientation.axis[ 0 ],
+ tnode->scaleOrientation.axis[ 1 ],
+ tnode->scaleOrientation.axis[ 2 ] );
+ trafo.Scale( tnode->scaleFactor.value[ 0 ],
+ tnode->scaleFactor.value[ 1 ],
+ tnode->scaleFactor.value[ 2 ] );
+ trafo.Rotate( tnode->scaleOrientation.angle,
+ tnode->scaleOrientation.axis[ 0 ],
+ tnode->scaleOrientation.axis[ 1 ],
+ tnode->scaleOrientation.axis[ 2 ] );
+ trafo.Rotate( tnode->rotation.angle,
+ tnode->rotation.axis[ 0 ],
+ tnode->rotation.axis[ 1 ],
+ tnode->rotation.axis[ 2 ] );
+ trafo.Translate( tnode->center.value[ 0 ],
+ tnode->center.value[ 1 ],
+ tnode->center.value[ 2 ] );
+ trafo.Translate( tnode->translation.value[ 0 ],
+ tnode->translation.value[ 1 ],
+ tnode->translation.value[ 2 ] );
+ } else if ( trafoelt->type == QvElement::MatrixTransform ) {
+ QvMatrixTransform *tnode = (QvMatrixTransform *) trafoelt->data;
+ Transform3 tmat( (const float(*)[4]) tnode->matrix.value );
+ trafo.Concat( tmat );
+ }
+ }
+}
+
+
+// accumulate current texture transformation stack into Transform2 object -----
+//
+void BRep::FetchTextureTransformationState( Transform2& trafo )
+{
+ trafo.LoadIdentity();
+
+ QvElement *trafoelt = m_state->getTopElement( QvState::Texture2TransformationIndex );
+ for ( ; trafoelt; trafoelt = trafoelt->next ) {
+
+ if ( trafoelt->type == QvElement::Unknown /*Transform*/ ) {
+
+ //NOTE:
+ // well, yes. QvLib really uses QvElement::Unknown as type
+ // for texture transformations!!
+
+ QvTexture2Transform *tnode = (QvTexture2Transform *) trafoelt->data;
+ trafo.Translate( -tnode->center.value[ 0 ],
+ -tnode->center.value[ 1 ] );
+ trafo.Scale( tnode->scaleFactor.value[ 0 ],
+ tnode->scaleFactor.value[ 1 ] );
+ trafo.Rotate( tnode->rotation.value );
+ trafo.Translate( tnode->center.value[ 0 ],
+ tnode->center.value[ 1 ] );
+ trafo.Translate( tnode->translation.value[ 0 ],
+ tnode->translation.value[ 1 ] );
+ }
+ }
+}
+
+
+// check current texture state; create new texture if necessary ---------------
+//
+Texture *BRep::CheckTexture2State()
+{
+ QvElement *elt = m_state->getTopElement( QvState::Texture2Index );
+
+ if ( elt == NULL )
+ return NULL;
+
+ // fetch texture node
+ QvTexture2 *tex = (QvTexture2 *) elt->data;
+ const char *texfilename = tex->filename.value.getString();
+
+ if ( ( texfilename == NULL ) || ( *texfilename == 0 ) )
+ return NULL;
+
+ // check if texture already exists
+ TextureChunk& texlist = m_baseobject->getTextureList();
+ for ( int i = 0; i < texlist.getNumElements(); i++ ) {
+ if ( strcmp( texlist[ i ].getFile(), texfilename ) == 0 )
+ return &texlist[ i ];
+ }
+
+ // default texture width and height are 1, yielding texture
+ // coordinates between 0.0 and 1.0 when multiplied by vrml
+ // texture coordinates later on.
+ int width = 1;
+ int height = 1;
+
+ // try to open texture file if it is in 3df format to read actual width and height
+ int namelen = strlen( texfilename );
+ if ( ( namelen > 4 ) && ( strcmp( texfilename + namelen - 4, ".3df" ) == 0 ) ) {
+
+ // open 3df file
+ FILE *fp = fopen( texfilename, "rb" );
+ if ( fp != NULL ) {
+
+ // header fields
+ char version[ 7 ];
+ char formatspec[ 11 ];
+ int lodsmall;
+ int lodlarge;
+ int aspectw;
+ int aspecth;
+
+ // scan out header
+ if ( fscanf( fp, "3df v%6s %10s lod range: %i %i aspect ratio: %i %i",
+ version, formatspec, &lodsmall, &lodlarge, &aspectw, &aspecth ) == 6 ) {
+
+ fclose( fp );
+
+ version[ 6 ] = 0;
+ formatspec[ 10 ] = 0;
+
+ // determine geometry
+ int aindx = ( aspectw << 4 ) | aspecth;
+ switch ( aindx ) {
+
+ case 0x81 :
+ width = lodlarge;
+ height = lodlarge / 8;
+ break;
+
+ case 0x41 :
+ width = lodlarge;
+ height = lodlarge / 4;
+ break;
+
+ case 0x21 :
+ width = lodlarge;
+ height = lodlarge / 2;
+ break;
+
+ case 0x11 :
+ width = lodlarge;
+ height = lodlarge;
+ break;
+
+ case 0x12 :
+ width = lodlarge / 2;
+ height = lodlarge;
+ break;
+
+ case 0x14 :
+ width = lodlarge / 4;
+ height = lodlarge;
+ break;
+
+ case 0x18 :
+ width = lodlarge / 8;
+ height = lodlarge;
+ break;
+
+ default :
+ break;
+ }
+ }
+ }
+
+ } else if ( ( namelen > 4 ) && ( strcmp( texfilename + namelen - 4, ".tga" ) == 0 ) ) {
+
+ // try to get width/height from .tga header
+
+ FILE *fp = fopen( texfilename, "rb" );
+ if ( fp != NULL ) {
+
+ tga_header_s header;
+
+ // read header
+ if ( fread( &header, 1, sizeof( tga_header_s ), fp ) == sizeof( tga_header_s ) ) {
+
+ width = ( header.WidthHi << 8 ) | header.WidthLo;
+ height = ( header.HeightHi << 8 ) | header.HeightLo;
+ }
+
+ fclose( fp );
+ }
+
+ } else if ( ( namelen > 4 ) && ( strcmp( texfilename + namelen - 4, ".jpg" ) == 0 ) ) {
+
+#ifdef USE_JPEG_LIBRARY
+
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+
+ FILE *fp = fopen( texfilename, "rb" );
+ if ( fp != NULL ) {
+
+ // specify error handler
+ cinfo.err = jpeg_std_error( &jerr );
+
+ // init decompressor
+ jpeg_create_decompress( &cinfo );
+
+ // specify the source for the compressed data
+ jpeg_stdio_src( &cinfo, fp );
+
+ // read jpeg header
+ jpeg_read_header( &cinfo, TRUE );
+
+ // de-init decompressor
+ jpeg_destroy_decompress( &cinfo );
+
+ fclose( fp );
+
+ width = cinfo.image_width;
+ height = cinfo.image_height;
+ }
+#else
+
+ fflush( stdout );
+ fprintf( stderr, "\nJPEG files are not supported by this version of makeodt.\n" );
+ fprintf( stderr, "If you need JPEG support, you can enable -DUSE_JPEG_LIBRARY\n" );
+ fprintf( stderr, "in the BspLib Makefile and recompile BspLib and makeodt.\n" );
+ fprintf( stderr, "This will require a working version of libjpeg 6.x\n" );
+ fprintf( stderr, "to be installed on your system.\n\n" );
+
+ exit( EXIT_FAILURE );
+#endif
+
+ }
+
+ Texture temptex( width, height );
+ temptex.setName( texfilename );
+ temptex.setFile( texfilename );
+ texlist.AddElement( temptex );
+
+ return &texlist[ texlist.getNumElements() - 1 ];
+}
+
+
+// retrieve material corresponding to specified index -------------------------
+//
+int BRep::FetchMaterialState( Material& mat, int indx )
+{
+ QvElement *elt = m_state->getTopElement( QvState::MaterialIndex );
+
+ if ( elt == NULL )
+ return 0;
+
+ // fetch material node
+ QvMaterial *m = (QvMaterial *) elt->data;
+
+ // determine period for binding
+ int ambnum = m->ambientColor.num;
+ int difnum = m->diffuseColor.num;
+ int spcnum = m->specularColor.num;
+ int eminum = m->emissiveColor.num;
+ int shinum = m->shininess.num;
+ int tranum = m->transparency.num;
+ int period = ambnum;
+ if ( difnum > period ) period = difnum;
+ if ( spcnum > period ) period = spcnum;
+ if ( eminum > period ) period = eminum;
+ if ( shinum > period ) period = shinum;
+ if ( tranum > period ) period = tranum;
+
+ ColorRGBA col;
+ col.A = 255;
+
+ int modindx = indx % period;
+ int readindx = ( modindx < ambnum ) ? modindx : ambnum - 1;
+ col.R = (byte)( m->ambientColor.values[ readindx * 3 + 0 ] * 255 );
+ col.G = (byte)( m->ambientColor.values[ readindx * 3 + 1 ] * 255 );
+ col.B = (byte)( m->ambientColor.values[ readindx * 3 + 2 ] * 255 );
+ mat.setAmbientColor( col );
+
+ readindx = ( modindx < difnum ) ? modindx : difnum - 1;
+ col.R = (byte)( m->diffuseColor.values[ readindx * 3 + 0 ] * 255 );
+ col.G = (byte)( m->diffuseColor.values[ readindx * 3 + 1 ] * 255 );
+ col.B = (byte)( m->diffuseColor.values[ readindx * 3 + 2 ] * 255 );
+ mat.setDiffuseColor( col );
+
+ readindx = ( modindx < spcnum ) ? modindx : spcnum - 1;
+ col.R = (byte)( m->specularColor.values[ readindx * 3 + 0 ] * 255 );
+ col.G = (byte)( m->specularColor.values[ readindx * 3 + 1 ] * 255 );
+ col.B = (byte)( m->specularColor.values[ readindx * 3 + 2 ] * 255 );
+ mat.setSpecularColor( col );
+
+ readindx = ( modindx < eminum ) ? modindx : eminum - 1;
+ col.R = (byte)( m->emissiveColor.values[ readindx * 3 + 0 ] * 255 );
+ col.G = (byte)( m->emissiveColor.values[ readindx * 3 + 1 ] * 255 );
+ col.B = (byte)( m->emissiveColor.values[ readindx * 3 + 2 ] * 255 );
+ mat.setEmissiveColor( col );
+
+ readindx = ( modindx < shinum ) ? modindx : shinum - 1;
+ mat.setShininess( m->shininess.values[ readindx ] );
+
+ readindx = ( modindx < tranum ) ? modindx : tranum - 1;
+ mat.setTransparency( m->transparency.values[ readindx ] );
+
+ return 1;
+}
+
+
+// fetch material binding -----------------------------------------------------
+//
+void BRep::FetchMaterialBindingState( int& binding )
+{
+ binding = QvMaterialBinding::DEFAULT;
+ QvElement *elt = m_state->getTopElement( QvState::MaterialBindingIndex );
+ if ( elt != NULL ) {
+ QvMaterialBinding *mb = (QvMaterialBinding *) elt->data;
+ binding = mb->value.value;
+ }
+}
+
+
+// fetch normal binding -------------------------------------------------------
+//
+void BRep::FetchNormalBindingState( int& binding )
+{
+ binding = QvMaterialBinding::DEFAULT;
+ QvElement *elt = m_state->getTopElement( QvState::NormalBindingIndex );
+ if ( elt != NULL ) {
+ QvNormalBinding *mb = (QvNormalBinding *) elt->data;
+ binding = mb->value.value;
+ }
+}
+
+
+// fetch shape hints information into static members --------------------------
+//
+void BRep::FetchShapeHintsState()
+{
+ QvElement *elt = m_state->getTopElement( QvState::ShapeHintsIndex );
+ if ( elt != NULL ) {
+ QvShapeHints *sh = (QvShapeHints *) elt->data;
+ shapehint_vertexOrdering = sh->vertexOrdering.value;
+ shapehint_shapeType = sh->shapeType.value;
+ shapehint_faceType = sh->faceType.value;
+ shapehint_creaseAngle = sh->creaseAngle.value;
+ }
+}
+
+
+// do b-rep construction post-processing --------------------------------------
+//
+void BRep::PostProcessObject()
+{
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+
+ int numvtxs = vtxlist.getNumElements();
+ if ( numvtxs > 0 ) {
+
+ // apply transformation matrix
+ // otherwise bounding box will not be correct!
+ m_baseobject->ApplyTransformation();
+
+ // determine object bounding box
+ Vertex3 minvertex;
+ Vertex3 maxvertex;
+ m_baseobject->CalcBoundingBox( minvertex, maxvertex );
+
+ // prepend bounding box to list of scene object bounding boxes
+ m_state->vrmlfile_base->m_bboxlist = new BoundingBox( minvertex, maxvertex, m_state->vrmlfile_base->m_bboxlist );
+
+ // set actual vertex correspondences (needs to be done after transformation!)
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ for ( int i = 0; i < facelist.getNumElements(); i++ ) {
+ if ( facelist[ i ].FaceTexMapped() ) {
+ // retrieve fake vertex containing corresponding vertex indexes
+ Vertex2 fake;
+ fake = facelist[ i ].MapXY( 0 );
+ // use vertex indexes to store actual correspondence coordinates
+ facelist[ i ].MapXY( 0 ).InitFromVertex3( vtxlist[ (int) fake.getX() ] );
+ facelist[ i ].MapXY( 1 ).InitFromVertex3( vtxlist[ (int) fake.getY() ] );
+ facelist[ i ].MapXY( 2 ).InitFromVertex3( vtxlist[ (int) fake.getW() ] );
+ }
+ }
+ }
+
+ m_baseobject->CheckParsedData();
+}
+
+
+// construct b-rep from vrml sphere primitive ---------------------------------
+//
+void BRep::BuildFromSpherePrimitive( const QvSphere& node )
+{
+ // base object
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ PolygonList& polylist = m_baseobject->getPolygonList();
+
+ // set possible transformation as object's local transformation
+ Transform3 trafo;
+ FetchTransformationState( trafo );
+ m_baseobject->setObjectTransformation( trafo );
+
+ int slices4 = tessellation_slices;
+
+ double radius = node.radius.value;
+
+ double phi = 0.0;
+ double phiinc = 1.570796327 / (double) slices4; // PI/2
+
+ // create circumference vertices
+ Vector3 basevec( radius, 0.0, 0.0 );
+ Vector3 scancircle( basevec );
+ int i = 0;
+ for ( i = 0; i < slices4; i++ ) {
+ vtxlist.AddVertex( scancircle );
+ phi += phiinc;
+ double cosphi = cos( phi );
+ double sinphi = sin( phi );
+ double nextx = cosphi * basevec.getX() + sinphi * basevec.getZ();
+ double nextz = sinphi * basevec.getX() + cosphi * basevec.getZ();
+ scancircle.setX( nextx );
+ scancircle.setZ( -nextz );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( vtxlist[ i ].getZ() );
+ nv.setY( vtxlist[ i ].getY() );
+ nv.setZ( -vtxlist[ i ].getX() );
+ vtxlist.AddVertex( nv );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( -vtxlist[ i ].getX() );
+ nv.setY( vtxlist[ i ].getY() );
+ nv.setZ( -vtxlist[ i ].getZ() );
+ vtxlist.AddVertex( nv );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( -vtxlist[ i ].getZ() );
+ nv.setY( vtxlist[ i ].getY() );
+ nv.setZ( vtxlist[ i ].getX() );
+ vtxlist.AddVertex( nv );
+ }
+
+ // create northern hemisphere
+ basevec = Vector3( radius, 0.0, 0.0 );
+ phi = 0.0;
+ for ( i = 1; i < slices4; i++ ) {
+ phi += phiinc;
+ double cosphi = cos( phi );
+ double sinphi = sin( phi );
+ double nextx = cosphi * basevec.getX() - sinphi * basevec.getY();
+ double nexty = sinphi * basevec.getX() + cosphi * basevec.getY();
+ double rfac = nextx / radius;
+ for ( int j = 0; j < slices4 * 4; j++ ) {
+ Vertex3 nv;
+ nv.setX( vtxlist[ j ].getX() * rfac );
+ nv.setY( nexty );
+ nv.setZ( vtxlist[ j ].getZ() * rfac );
+ vtxlist.AddVertex( nv );
+ }
+ }
+
+ // create southern hemisphere
+ basevec = Vector3( radius, 0.0, 0.0 );
+ phi = 0.0;
+ for ( i = 1; i < slices4; i++ ) {
+ phi += phiinc;
+ double cosphi = cos( phi );
+ double sinphi = sin( phi );
+ double nextx = cosphi * basevec.getX() - sinphi * basevec.getY();
+ double nexty = sinphi * basevec.getX() + cosphi * basevec.getY();
+ double rfac = nextx / radius;
+ for ( int j = 0; j < slices4 * 4; j++ ) {
+ Vertex3 nv;
+ nv.setX( vtxlist[ j ].getX() * rfac );
+ nv.setY( -nexty );
+ nv.setZ( vtxlist[ j ].getZ() * rfac );
+ vtxlist.AddVertex( nv );
+ }
+ }
+
+ // create pole vertices
+ int p1indx = vtxlist.AddVertex( Vertex3( 0.0, radius, 0.0 ) );
+ int p2indx = vtxlist.AddVertex( Vertex3( 0.0, -radius, 0.0 ) );
+
+ // create polygons for side
+ int faceid = 0;
+ int j = 0;
+ for ( j = 0; j < slices4 - 1; j++ ) {
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ // create side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + j * slices4 * 4 );
+ sidepoly->AppendNewVIndx( i + ( j + 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( i + ( j + 1 ) * slices4 * 4 + 1 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + ( j + 1 ) * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + j * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + j * slices4 * 4 );
+ }
+
+ // create last side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + j * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + ( j + 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( ( j + 1 ) * slices4 * 4 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( ( j + 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( j * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + j * slices4 * 4 );
+ }
+
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ // create side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i );
+ sidepoly->AppendNewVIndx( i + 1 );
+ sidepoly->AppendNewVIndx( i + slices4 * slices4 * 4 + 1 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + slices4 * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + slices4 * slices4 * 4 );
+ sidepoly->AppendNewVIndx( i );
+ }
+
+ // create last side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 );
+ sidepoly->AppendNewVIndx( 0 );
+ sidepoly->AppendNewVIndx( slices4 * slices4 * 4 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( slices4 * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + slices4 * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 );
+
+
+ for ( j = slices4; j < 2 * slices4 - 2; j++ ) {
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ // create side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + j * slices4 * 4 );
+ sidepoly->AppendNewVIndx( i + j * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + ( j + 1 ) * slices4 * 4 + 1 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + ( j + 1 ) * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + ( j + 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( i + j * slices4 * 4 );
+ }
+
+ // create last side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + j * slices4 * 4 );
+ sidepoly->AppendNewVIndx( j * slices4 * 4 );
+ sidepoly->AppendNewVIndx( ( j + 1 ) * slices4 * 4 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( ( j + 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + ( j + 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + j * slices4 * 4 );
+ }
+
+ // create polygons for poles
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + ( slices4 - 1 ) * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + ( slices4 - 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( p1indx );
+ }
+ {
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( ( slices4 - 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + ( slices4 - 1 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( p1indx );
+ }
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( i + ( 2 * slices4 - 2 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( i + ( 2 * slices4 - 2 ) * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( p2indx );
+ }
+ {
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( faceid++ );
+ sidepoly->AppendNewVIndx( slices4 * 4 - 1 + ( 2 * slices4 - 2 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( ( 2 * slices4 - 2 ) * slices4 * 4 );
+ sidepoly->AppendNewVIndx( p2indx );
+ }
+
+ // the sphere primitive ignores the current material binding!
+ // therefore fetch only the first material
+ Material mat;
+ int matvalid = FetchMaterialState( mat, 0 );
+
+ // create faces
+ for ( i = 0; i < polylist.getNumElements(); i++ ) {
+ Face tempface;
+ if ( matvalid ) {
+ if ( use_material_spec ) {
+ // attach material specification
+ tempface.setShadingType( Face::material_shad );
+ tempface.AttachMaterial( new Material( mat ) );
+ } else {
+ // use gouraud_shad with diffuse color
+ tempface.setShadingType( Face::gouraud_shad );
+ tempface.setFaceColor( mat.getDiffuseColor() );
+ }
+ } else {
+ // use no_shad with index 255 if no material in state
+ tempface.setShadingType( Face::no_shad );
+ tempface.setFaceColor( 255 );
+ }
+
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+ }
+
+ // do post-processing after object has been built
+ PostProcessObject();
+}
+
+
+// construct b-rep from vrml cone primitive -----------------------------------
+//
+void BRep::BuildFromConePrimitive( const QvCone& node )
+{
+ // base object
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ PolygonList& polylist = m_baseobject->getPolygonList();
+
+ // set possible transformation as object's local transformation
+ Transform3 trafo;
+ FetchTransformationState( trafo );
+ m_baseobject->setObjectTransformation( trafo );
+
+ int slices4 = tessellation_slices;
+
+ double radius = node.bottomRadius.value;
+ double top_y = node.height.value / 2;
+ double bottom_y = - node.height.value / 2;
+
+ double phi = 0.0;
+ double phiinc = 1.570796327 / (double) slices4; // PI/2
+
+ // create bottom plate vertices
+ Vector3 basevec( radius, bottom_y, 0.0 );
+ Vector3 scancircle( basevec );
+ vtxlist.AddVertex( Vertex3( 0.0, bottom_y, 0.0 ) );
+ int i = 0;
+ for ( i = 0; i < slices4; i++ ) {
+ vtxlist.AddVertex( scancircle );
+ phi += phiinc;
+ double cosphi = cos( phi );
+ double sinphi = sin( phi );
+ double nextx = cosphi * basevec.getX() + sinphi * basevec.getZ();
+ double nextz = sinphi * basevec.getX() + cosphi * basevec.getZ();
+ scancircle.setX( nextx );
+ scancircle.setZ( -nextz );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( vtxlist[ i + 1 ].getZ() );
+ nv.setY( vtxlist[ i + 1 ].getY() );
+ nv.setZ( -vtxlist[ i + 1 ].getX() );
+ vtxlist.AddVertex( nv );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( -vtxlist[ i + 1 ].getX() );
+ nv.setY( vtxlist[ i + 1 ].getY() );
+ nv.setZ( -vtxlist[ i + 1 ].getZ() );
+ vtxlist.AddVertex( nv );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( -vtxlist[ i + 1 ].getZ() );
+ nv.setY( vtxlist[ i + 1 ].getY() );
+ nv.setZ( vtxlist[ i + 1 ].getX() );
+ vtxlist.AddVertex( nv );
+ }
+
+ // create top vertex
+ vtxlist.AddVertex( Vertex3( 0.0, top_y, 0.0 ) );
+
+ // create polygons
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ // create bottom plate polygon
+ Polygon *bottompoly = polylist.NewPolygon();
+ bottompoly->setFaceId( 0 );
+ bottompoly->AppendNewVIndx( i + 1 );
+ bottompoly->AppendNewVIndx( i + 2 );
+ bottompoly->AppendNewVIndx( 0 );
+ // create side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( i + 1 );
+ sidepoly->AppendNewVIndx( i + 1 );
+ sidepoly->AppendNewVIndx( slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( i + 2 );
+ }
+
+ {
+ // create last bottom plate polygon
+ Polygon *bottompoly = polylist.NewPolygon();
+ bottompoly->setFaceId( 0 );
+ bottompoly->AppendNewVIndx( slices4 * 4 );
+ bottompoly->AppendNewVIndx( 1 );
+ bottompoly->AppendNewVIndx( 0 );
+ // create last side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 );
+ sidepoly->AppendNewVIndx( slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( 1 );
+ }
+
+ // fetch the first two materials
+ Material mat1, mat2;
+ int mat1valid = FetchMaterialState( mat1, 0 );
+ int mat2valid = FetchMaterialState( mat2, 1 );
+
+ // fetch the current material binding
+ int currentbinding;
+ FetchMaterialBindingState( currentbinding );
+
+ // apply material binding
+ if ( currentbinding != QvMaterialBinding::PER_PART &&
+ currentbinding != QvMaterialBinding::PER_PART_INDEXED ) {
+ mat2 = mat1;
+ mat2valid = mat1valid;
+ }
+
+ // create faces
+ for ( i = 0; i < slices4 * 4 + 1; i++ ) {
+
+ //NOTE:
+ // there are ( slices4 * 4 + 1 ) faces.
+ // the bottom plate is a single face although it consists
+ // of ( slices4 * 4 ) polygons.
+
+ Face tempface;
+ if ( mat1valid && mat2valid ) {
+ if ( use_material_spec ) {
+ // attach material specification
+ tempface.setShadingType( Face::material_shad );
+ if ( i == 0 )
+ tempface.AttachMaterial( new Material( mat2 ) );
+ else
+ tempface.AttachMaterial( new Material( mat1 ) );
+ } else {
+ // use gouraud_shad with diffuse color
+ tempface.setShadingType( Face::gouraud_shad );
+ if ( i == 0 )
+ tempface.setFaceColor( mat2.getDiffuseColor() );
+ else
+ tempface.setFaceColor( mat1.getDiffuseColor() );
+ }
+ } else {
+ // use no_shad with index 255 if no material in state
+ tempface.setShadingType( Face::no_shad );
+ tempface.setFaceColor( 255 );
+ }
+
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+ }
+
+ // do post-processing after object has been built
+ PostProcessObject();
+}
+
+
+// construct b-rep from vrml cylinder primitive -------------------------------
+//
+void BRep::BuildFromCylinderPrimitive( const QvCylinder& node )
+{
+ // base object
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ PolygonList& polylist = m_baseobject->getPolygonList();
+
+ // set possible transformation as object's local transformation
+ Transform3 trafo;
+ FetchTransformationState( trafo );
+ m_baseobject->setObjectTransformation( trafo );
+
+ int slices4 = tessellation_slices;
+
+ double radius = node.radius.value;
+ double top_y = node.height.value / 2;
+ double bottom_y = - node.height.value / 2;
+
+ double phi = 0.0;
+ double phiinc = 1.570796327 / (double) slices4; // PI/2
+
+ // create bottom plate vertices
+ Vector3 basevec( radius, bottom_y, 0.0 );
+ Vector3 scancircle( basevec );
+ vtxlist.AddVertex( Vertex3( 0.0, bottom_y, 0.0 ) );
+ int i = 0;
+ for ( i = 0; i < slices4; i++ ) {
+ vtxlist.AddVertex( scancircle );
+ phi += phiinc;
+ double cosphi = cos( phi );
+ double sinphi = sin( phi );
+ double nextx = cosphi * basevec.getX() + sinphi * basevec.getZ();
+ double nextz = sinphi * basevec.getX() + cosphi * basevec.getZ();
+ scancircle.setX( nextx );
+ scancircle.setZ( -nextz );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( vtxlist[ i + 1 ].getZ() );
+ nv.setY( vtxlist[ i + 1 ].getY() );
+ nv.setZ( -vtxlist[ i + 1 ].getX() );
+ vtxlist.AddVertex( nv );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( -vtxlist[ i + 1 ].getX() );
+ nv.setY( vtxlist[ i + 1 ].getY() );
+ nv.setZ( -vtxlist[ i + 1 ].getZ() );
+ vtxlist.AddVertex( nv );
+ }
+ for ( i = 0; i < slices4; i++ ) {
+ Vertex3 nv;
+ nv.setX( -vtxlist[ i + 1 ].getZ() );
+ nv.setY( vtxlist[ i + 1 ].getY() );
+ nv.setZ( vtxlist[ i + 1 ].getX() );
+ vtxlist.AddVertex( nv );
+ }
+
+ // create top plate vertices
+ vtxlist.AddVertex( Vertex3( 0.0, top_y, 0.0 ) );
+ for ( i = 0; i < slices4 * 4; i++ ) {
+ Vertex3 nv( vtxlist[ i + 1 ] );
+ nv.setY( top_y );
+ vtxlist.AddVertex( nv );
+ }
+
+ // create polygons
+ for ( i = 0; i < slices4 * 4 - 1; i++ ) {
+ // create bottom plate polygon
+ Polygon *bottompoly = polylist.NewPolygon();
+ bottompoly->setFaceId( 0 );
+ bottompoly->AppendNewVIndx( i + 1 );
+ bottompoly->AppendNewVIndx( i + 2 );
+ bottompoly->AppendNewVIndx( 0 );
+ // create top plate polygon
+ Polygon *toppoly = polylist.NewPolygon();
+ toppoly->setFaceId( 1 );
+ toppoly->AppendNewVIndx( i + slices4 * 4 + 3 );
+ toppoly->AppendNewVIndx( i + slices4 * 4 + 2 );
+ toppoly->AppendNewVIndx( slices4 * 4 + 1 );
+ // create side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( i + 2 );
+ sidepoly->AppendNewVIndx( i + 1 );
+ sidepoly->AppendNewVIndx( i + slices4 * 4 + 2 );
+ sidepoly->AppendNewVIndx( i + slices4 * 4 + 3 );
+ sidepoly->AppendNewVIndx( i + 2 );
+ }
+
+ {
+ // create last bottom plate polygon
+ Polygon *bottompoly = polylist.NewPolygon();
+ bottompoly->setFaceId( 0 );
+ bottompoly->AppendNewVIndx( slices4 * 4 );
+ bottompoly->AppendNewVIndx( 1 );
+ bottompoly->AppendNewVIndx( 0 );
+ // create last top plate polygon
+ Polygon *toppoly = polylist.NewPolygon();
+ toppoly->setFaceId( 1 );
+ toppoly->AppendNewVIndx( slices4 * 4 + 2 );
+ toppoly->AppendNewVIndx( 2 * slices4 * 4 + 1 );
+ toppoly->AppendNewVIndx( slices4 * 4 + 1 );
+ // create last side polygon
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->setFaceId( slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( slices4 * 4 );
+ sidepoly->AppendNewVIndx( 2 * slices4 * 4 + 1 );
+ sidepoly->AppendNewVIndx( slices4 * 4 + 2 );
+ sidepoly->AppendNewVIndx( 1 );
+ }
+
+ // fetch the first three materials
+ Material mat1, mat2, mat3;
+ int mat1valid = FetchMaterialState( mat1, 0 );
+ int mat2valid = FetchMaterialState( mat2, 1 );
+ int mat3valid = FetchMaterialState( mat3, 2 );
+
+ // fetch the current material binding
+ int currentbinding;
+ FetchMaterialBindingState( currentbinding );
+
+ // apply material binding
+ if ( currentbinding != QvMaterialBinding::PER_PART &&
+ currentbinding != QvMaterialBinding::PER_PART_INDEXED ) {
+ mat2 = mat1;
+ mat3 = mat1;
+ mat2valid = mat1valid;
+ mat3valid = mat1valid;
+ }
+
+ // create faces
+ for ( i = 0; i < slices4 * 4 + 2; i++ ) {
+ Face tempface;
+
+ //NOTE:
+ // there are ( slices4 * 4 + 2 ) faces.
+ // the bottom and top plates are each a single face although
+ // they each consist of ( slices4 * 4 ) polygons.
+
+ if ( mat1valid && mat2valid && mat3valid ) {
+ if ( use_material_spec ) {
+ // attach material specification
+ tempface.setShadingType( Face::material_shad );
+ if ( i == 0 )
+ tempface.AttachMaterial( new Material( mat3 ) );
+ else if ( i == 1 )
+ tempface.AttachMaterial( new Material( mat2 ) );
+ else
+ tempface.AttachMaterial( new Material( mat1 ) );
+ } else {
+ // use gouraud_shad with diffuse color
+ tempface.setShadingType( Face::gouraud_shad );
+ if ( i == 0 )
+ tempface.setFaceColor( mat3.getDiffuseColor() );
+ else if ( i == 1 )
+ tempface.setFaceColor( mat2.getDiffuseColor() );
+ else
+ tempface.setFaceColor( mat1.getDiffuseColor() );
+ }
+ } else {
+ // use no_shad with index 255 if no material in state
+ tempface.setShadingType( Face::no_shad );
+ tempface.setFaceColor( 255 );
+ }
+
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+ }
+
+ // do post-processing after object has been built
+ PostProcessObject();
+}
+
+
+// construct b-rep from vrml cube primitive -----------------------------------
+//
+void BRep::BuildFromCubePrimitive( const QvCube& node )
+{
+ // base object
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ PolygonList& polylist = m_baseobject->getPolygonList();
+
+ // set possible transformation as object's local transformation
+ Transform3 trafo;
+ FetchTransformationState( trafo );
+ m_baseobject->setObjectTransformation( trafo );
+
+ double max_x = node.width.value / 2;
+ double max_y = node.height.value / 2;
+ double max_z = node.depth.value / 2;
+
+ vtxlist.AddVertex( Vertex3( -max_x, max_y, max_z ) );
+ vtxlist.AddVertex( Vertex3( max_x, max_y, max_z ) );
+ vtxlist.AddVertex( Vertex3( max_x, -max_y, max_z ) );
+ vtxlist.AddVertex( Vertex3( -max_x, -max_y, max_z ) );
+
+ vtxlist.AddVertex( Vertex3( -max_x, max_y, -max_z ) );
+ vtxlist.AddVertex( Vertex3( -max_x, -max_y, -max_z ) );
+ vtxlist.AddVertex( Vertex3( max_x, -max_y, -max_z ) );
+ vtxlist.AddVertex( Vertex3( max_x, max_y, -max_z ) );
+
+ Polygon *sidepoly = polylist.NewPolygon();
+ sidepoly->AppendNewVIndx( 0 ); sidepoly->AppendNewVIndx( 1 ); sidepoly->AppendNewVIndx( 2 ); sidepoly->AppendNewVIndx( 3 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->AppendNewVIndx( 1 ); sidepoly->AppendNewVIndx( 7 ); sidepoly->AppendNewVIndx( 6 ); sidepoly->AppendNewVIndx( 2 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->AppendNewVIndx( 7 ); sidepoly->AppendNewVIndx( 4 ); sidepoly->AppendNewVIndx( 5 ); sidepoly->AppendNewVIndx( 6 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->AppendNewVIndx( 4 ); sidepoly->AppendNewVIndx( 0 ); sidepoly->AppendNewVIndx( 3 ); sidepoly->AppendNewVIndx( 5 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->AppendNewVIndx( 3 ); sidepoly->AppendNewVIndx( 2 ); sidepoly->AppendNewVIndx( 6 ); sidepoly->AppendNewVIndx( 5 );
+ sidepoly = polylist.NewPolygon();
+ sidepoly->AppendNewVIndx( 1 ); sidepoly->AppendNewVIndx( 0 ); sidepoly->AppendNewVIndx( 4 ); sidepoly->AppendNewVIndx( 7 );
+
+ //TODO:
+ // polygons have to be created in the order prescribed by
+ // material application!
+
+ // fetch the first six materials
+ Material mats[ 6 ];
+ int matsvalid[ 6 ];
+ int i = 0;
+ for ( i = 0; i < 6; i++ )
+ matsvalid[ i ] = FetchMaterialState( mats[ i ], 0 );
+
+ // fetch the current material binding
+ int currentbinding;
+ FetchMaterialBindingState( currentbinding );
+
+ // apply material binding
+ if ( currentbinding != QvMaterialBinding::PER_PART &&
+ currentbinding != QvMaterialBinding::PER_PART_INDEXED &&
+ currentbinding != QvMaterialBinding::PER_FACE &&
+ currentbinding != QvMaterialBinding::PER_FACE_INDEXED )
+ for ( i = 1; i < 6; i++ ) {
+ mats[ i ] = mats[ 0 ];
+ matsvalid[ i ] = matsvalid[ 0 ];
+ }
+
+ // check validity of all materials
+ int allmatsvalid = 1;
+ for ( i = 0; i < 6; i++ )
+ if ( !matsvalid[ i ] )
+ allmatsvalid = 0;
+
+ // create faces
+ for ( i = 0; i < 6; i++ ) {
+ Face tempface;
+
+ if ( allmatsvalid ) {
+ if ( use_material_spec ) {
+ // attach material specification
+ tempface.setShadingType( Face::material_shad );
+ tempface.AttachMaterial( new Material( mats[ i ] ) );
+ } else {
+ // use gouraud_shad with diffuse color
+ tempface.setShadingType( Face::gouraud_shad );
+ tempface.setFaceColor( mats[ i ].getDiffuseColor() );
+ }
+ } else {
+ // use no_shad with index 255 if no material in state
+ tempface.setShadingType( Face::no_shad );
+ tempface.setFaceColor( 255 );
+ }
+
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+ }
+
+ // do post-processing after object has been built
+ PostProcessObject();
+}
+
+
+// create single face for specification in indexed face set -------------------
+//
+void BRep::CreateIndexedFace( Texture *texture, int curindex, int numtexindexs, long *texindexs, int v1, int v2, int v3 )
+{
+ // base object
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ FaceChunk& facelist = m_baseobject->getFaceList();
+
+ // face to be created
+ Face tempface;
+
+ // fetch material
+ Material mat;
+ int matvalid = FetchMaterialState( mat, 0 );
+
+ if ( matvalid ) {
+ if ( use_material_spec ) {
+ // attach material specification
+ tempface.setShadingType( Face::material_shad );
+ tempface.AttachMaterial( new Material( mat ) );
+ } else {
+ // use gouraud_shad with diffuse color
+ tempface.setShadingType( Face::gouraud_shad );
+ tempface.setFaceColor( mat.getDiffuseColor() );
+ }
+ } else {
+ // use no_shad with index 255 if no material in state
+ tempface.setShadingType( Face::no_shad );
+ tempface.setFaceColor( 255 );
+ }
+
+ // check if face is textured
+ if ( texture != NULL ) {
+ int coordsnum;
+ float *texcoords = FetchTextureCoordinate2State( coordsnum );
+
+ // fetch (u,v) transformation
+ Transform2 trafo;
+ FetchTextureTransformationState( trafo );
+
+ // store fake vertex containing corresponding vertex indexes
+ Vertex2 fake( v1, v2, v3 );
+ tempface.MapXY( 0 ) = fake;
+
+ int mappingvalid = 0;
+
+ int coordindx = ( curindex - 3 < numtexindexs ) ? texindexs[ curindex - 3 ] : -1;
+ if ( ( coordindx >= 0 ) && ( coordindx < coordsnum ) ) {
+ tempface.MapUV( 0 ).setX( texcoords[ coordindx * 2 + 0 ] );
+ tempface.MapUV( 0 ).setY( texcoords[ coordindx * 2 + 1 ] );
+ tempface.MapUV( 0 ).setW( 1.0 );
+ Vertex2 tv = trafo.TransformVector2( tempface.MapUV( 0 ) );
+ tv.setX( tv.getX() * texture->getWidth() );
+ double ucoord = mirror_v_axis ? ( 1.0 - tv.getY() ) : tv.getY();
+ tv.setY( ucoord * texture->getHeight() );
+ tempface.MapUV( 0 ) = tv;
+ mappingvalid++;
+ }
+
+ coordindx = ( curindex - 2 < numtexindexs ) ? texindexs[ curindex - 2 ] : -1;
+ if ( ( coordindx >= 0 ) && ( coordindx < coordsnum ) ) {
+ tempface.MapUV( 1 ).setX( texcoords[ coordindx * 2 + 0 ] );
+ tempface.MapUV( 1 ).setY( texcoords[ coordindx * 2 + 1 ] );
+ tempface.MapUV( 1 ).setW( 1.0 );
+ Vertex2 tv = trafo.TransformVector2( tempface.MapUV( 1 ) );
+ tv.setX( tv.getX() * texture->getWidth() );
+ double ucoord = mirror_v_axis ? ( 1.0 - tv.getY() ) : tv.getY();
+ tv.setY( ucoord * texture->getHeight() );
+ tempface.MapUV( 1 ) = tv;
+ mappingvalid++;
+ }
+
+ coordindx = ( curindex - 1 < numtexindexs ) ? texindexs[ curindex - 1 ] : -1;
+ if ( ( coordindx >= 0 ) && ( coordindx < coordsnum ) ) {
+ tempface.MapUV( 2 ).setX( texcoords[ coordindx * 2 + 0 ] );
+ tempface.MapUV( 2 ).setY( texcoords[ coordindx * 2 + 1 ] );
+ tempface.MapUV( 2 ).setW( 1.0 );
+ Vertex2 tv = trafo.TransformVector2( tempface.MapUV( 2 ) );
+ tv.setX( tv.getX() * texture->getWidth() );
+ double ucoord = mirror_v_axis ? ( 1.0 - tv.getY() ) : tv.getY();
+ tv.setY( ucoord * texture->getHeight() );
+ tempface.MapUV( 2 ) = tv;
+ mappingvalid++;
+ }
+
+ // only set shading type to textured if all three
+ // mapping coordinates valid
+ if ( mappingvalid == 3 ) {
+ tempface.setShadingType( Face::ipol1tex_shad );
+ tempface.setTextureName( texture->getName() );
+ }
+ }
+
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+}
+
+
+// construct b-rep from vrml indexed face set ---------------------------------
+//
+void BRep::BuildFromIndexedFaceSet( const QvIndexedFaceSet& faceset )
+{
+ // check current shape hints
+ FetchShapeHintsState();
+
+ // check for texture mapping
+ Texture *texture = CheckTexture2State();
+
+ // determine number and address of vertices in current state
+ int numvertices;
+ float *vertices = FetchCoordinate3State( numvertices );
+
+ // base object
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ PolygonList& polylist = m_baseobject->getPolygonList();
+
+ // set possible transformation as object's local transformation
+ Transform3 trafo;
+ FetchTransformationState( trafo );
+ m_baseobject->setObjectTransformation( trafo );
+
+ // create vertices (regardless of usage)
+ for ( int i = 0; i < numvertices; i++ ) {
+ double x = vertices[ i * 3 + 0 ];
+ double y = vertices[ i * 3 + 1 ];
+ double z = vertices[ i * 3 + 2 ];
+ vtxlist.AddVertex( Vertex3( x, y, z ) );
+ }
+
+ //TODO:
+ // all vertices are included in every object, regardless of usage!
+
+ // fetch the current material binding
+ int currentbinding;
+ FetchMaterialBindingState( currentbinding );
+
+ // determine number and address of vertex indexes
+ int numvtxindexs = faceset.coordIndex.num;
+ long *vtxindexs = faceset.coordIndex.values;
+
+ // determine number and address of material indexes
+ int nummatindexs = faceset.materialIndex.num;
+ long *matindexs = faceset.materialIndex.values;
+
+ // determine number and address of normal indexes
+ int numnmlindexs = faceset.normalIndex.num;
+ long *nmlindexs = faceset.normalIndex.values;
+
+ // determine number and address of texture coordinate indexes
+ int numtexindexs = faceset.textureCoordIndex.num;
+ long *texindexs = faceset.textureCoordIndex.values;
+
+ // create polygons and faces
+ int vtxsread = 0;
+ int polysread = 0; // this also counts polygons removed due to degeneracy!
+ int v1, v2, v3;
+ Plane curplane;
+ while ( numvtxindexs > 0 ) {
+
+ // prepend new polygon to list
+ Polygon *poly = polylist.NewPolygon();
+
+ // create vertexlist for this polygon
+ int vtxcount = 0;
+ while ( numvtxindexs-- > 0 ) {
+ // read next vertex index
+ int vindx = *vtxindexs++;
+ vtxsread++;
+ vtxcount++;
+ // -1 is end marker for face
+ if ( vindx == -1 )
+ break;
+ if ( vindx >= numvertices ) {
+ {
+ StrScratch message;
+ sprintf( message, "**ERROR** [Specified vertex-index invalid]: %d\n", vindx );
+ ErrorMessage( message );
+ }
+ HandleCriticalError();
+ }
+
+ if ( vtxcount == 1 ) {
+ // store first vertex index
+ v1 = vindx;
+ } else if ( vtxcount == 2 ) {
+ // store second vertex index
+ v2 = vindx;
+ } else if ( vtxcount == 3 ) {
+ // store third vertex index
+ v3 = vindx;
+ // create plane for polygon (sidedness irrelevant!)
+ curplane.InitPlane( vtxlist[ v1 ], vtxlist[ v2 ], vtxlist[ v3 ] );
+ // count original polygons (including degenerate ones!)
+ polysread++;
+ // check if plane valid
+ if ( !curplane.PlaneValid() ) {
+ // remove polygon if invalid
+ polylist.DeleteHead();
+ // skip possibly remaining vertexindexes
+ while ( ( numvtxindexs-- > 0 ) && ( *vtxindexs++ != -1 ) )
+ vtxsread++;
+ vtxindexs--;
+ numvtxindexs++;
+ continue;
+ }
+ // create face
+ CreateIndexedFace( texture, vtxsread, numtexindexs, texindexs, v1, v2, v3 );
+// } else if ( vtxcount == 4 ) {
+ } else {
+ // create new polygon and face if next point not contained in
+ // previous triangle's plane or triangulation explicitly desired
+ if ( !curplane.PointContained( vtxlist[ vindx ] ) || do_triangulation ) {
+ // add new polygon to list
+ poly = polylist.NewPolygon();
+ if ( shapehint_vertexOrdering == QvShapeHints::CLOCKWISE ) {
+ polylist.AppendNewVIndx( v1 );
+ polylist.AppendNewVIndx( v3 );
+ } else {
+ polylist.PrependNewVIndx( v1 );
+ polylist.PrependNewVIndx( v3 );
+ }
+ // create plane for polygon
+ curplane.InitPlane( vtxlist[ v1 ], vtxlist[ v3 ], vtxlist[ vindx ] );
+ // check if plane valid
+ if ( !curplane.PlaneValid() ) {
+ // remove polygon if invalid
+ polylist.DeleteHead();
+ // skip possibly remaining vertexindexes
+ while ( ( numvtxindexs-- > 0 ) && ( *vtxindexs++ != -1 ) )
+ vtxsread++;
+ vtxindexs--;
+ numvtxindexs++;
+ continue;
+ }
+ // create face
+ CreateIndexedFace( texture, vtxsread, numtexindexs, texindexs, v1, v2, v3 );
+ }
+ // advance triangle fan
+ v3 = vindx;
+ }
+
+ // insert current vertex index into polygon
+ if ( shapehint_vertexOrdering == QvShapeHints::CLOCKWISE )
+ polylist.AppendNewVIndx( vindx );
+ else
+ polylist.PrependNewVIndx( vindx );
+ }
+
+ if ( polylist.FetchHead() != NULL ) {
+
+ //NOTE:
+ // if all polygons up to now have been removed due to degeneracy,
+ // polylist might contain not a single element! therefore,
+ // getNumVertices() cannot be used!
+
+ // check if polygon is at least triangle
+ if ( polylist.getNumVertices() < 3 ) {
+ {
+ StrScratch message;
+ sprintf( message, "**ERROR** [Face must have at least 3 vertices]: %d\n",
+ polylist.getNumElements() );
+ ErrorMessage( message );
+ }
+ HandleCriticalError();
+ }
+
+ } else {
+ StrScratch message;
+ sprintf( message, "**ERROR** [Polygon is degenerate]: %d\n", polysread );
+ ErrorMessage( message );
+ }
+ }
+
+ // do post-processing after object has been built
+ PostProcessObject();
+}
+
+
+// shape hints ----------------------------------------------------------------
+//
+int BRep::shapehint_vertexOrdering = QvShapeHints::UNKNOWN_ORDERING;
+int BRep::shapehint_shapeType = QvShapeHints::UNKNOWN_SHAPE_TYPE;
+int BRep::shapehint_faceType = QvShapeHints::CONVEX;
+float BRep::shapehint_creaseAngle = 0.5f;
+
+
+// full material specification usage control ----------------------------------
+//
+int BRep::use_material_spec = FALSE;
+
+
+// flag if v axis should be mirrored for texture coordinates ------------------
+//
+int BRep::mirror_v_axis = TRUE;
+
+
+// triangulation control ------------------------------------------------------
+//
+int BRep::do_triangulation = FALSE;
+
+
+// tessellation resolution in slices per PI/2 ---------------------------------
+//
+int BRep::tessellation_slices = 4;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BRep.h b/tool_src/BspLib/BRep.h
new file mode 100644
index 0000000..57fff2c
--- /dev/null
+++ b/tool_src/BspLib/BRep.h
@@ -0,0 +1,93 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BRep.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BREP_H_
+#define _BREP_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObjectList.h"
+#include "BoundingBox.h"
+#include "SystemIO.h"
+#include "Transform2.h"
+#include "Transform3.h"
+
+// qvlib header files
+#include <QvState.h>
+#include <QvSphere.h>
+#include <QvCone.h>
+#include <QvCube.h>
+#include <QvCylinder.h>
+#include <QvIndexedFaceSet.h>
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// b-rep class; used by vrml tree traversal to construct objects --------------
+//
+class BRep : public virtual SystemIO {
+
+public:
+ BRep( QvState *state );
+ ~BRep() { }
+
+ void BuildFromSpherePrimitive( const QvSphere& spherenode );
+ void BuildFromConePrimitive( const QvCone& spherenode );
+ void BuildFromCubePrimitive( const QvCube& spherenode );
+ void BuildFromCylinderPrimitive( const QvCylinder& spherenode );
+ void BuildFromIndexedFaceSet( const QvIndexedFaceSet& faceset );
+
+public:
+ static int getTriangulation() { return do_triangulation; }
+ static void setTriangulation( int tri ) { do_triangulation = tri; }
+
+ static int getTessellation() { return tessellation_slices; }
+ static void setTessellation( int tes ) { tessellation_slices = tes; }
+
+ static int getMaterialFlag() { return use_material_spec; }
+ static void setMaterialFlag( int mfl ) { use_material_spec = mfl; }
+
+ static int getMirrorTextureVFlag() { return mirror_v_axis; }
+ static void setMirrorTextureVFlag( int mtv ) { mirror_v_axis = mtv; }
+
+private:
+ float* FetchCoordinate3State( int &num );
+ float* FetchTextureCoordinate2State( int &num );
+ float* FetchNormalState( int &num );
+ void FetchTransformationState( Transform3& trafo );
+ void FetchTextureTransformationState( Transform2& trafo );
+ int FetchMaterialState( Material& mat, int indx );
+ void FetchMaterialBindingState( int& binding );
+ void FetchNormalBindingState( int& binding );
+ void FetchShapeHintsState();
+ Texture* CheckTexture2State();
+ void CreateIndexedFace( Texture *texture, int curindex, int numtexindexs, long *texindexs, int v1, int v2, int v3 );
+ void PostProcessObject();
+
+private:
+ static int shapehint_vertexOrdering;
+ static int shapehint_shapeType;
+ static int shapehint_faceType;
+ static float shapehint_creaseAngle;
+
+ static int use_material_spec;
+ static int mirror_v_axis;
+ static int do_triangulation;
+ static int tessellation_slices;
+
+private:
+ QvState* m_state;
+ BspObject* m_baseobject;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BREP_H_
+
diff --git a/tool_src/BspLib/BSPNode.cpp b/tool_src/BspLib/BSPNode.cpp
new file mode 100644
index 0000000..4edd283
--- /dev/null
+++ b/tool_src/BspLib/BSPNode.cpp
@@ -0,0 +1,401 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BSPNode.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BSPNode.h"
+#include "BoundingBox.h"
+#include "BspFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct BSPNode ----------------------------------------------------------
+//
+BSPNode::BSPNode( BSPNode *front, BSPNode *back, Polygon *poly, Polygon *backpoly, Plane *sep, BoundingBox *box, int num )
+{
+ frontsubtree = front;
+ backsubtree = back;
+ polygon = poly;
+ backpolygon = backpoly;
+ separatorplane = sep;
+ boundingbox = box;
+ nodenumber = num;
+}
+
+
+// destroy BSPNode ------------------------------------------------------------
+//
+BSPNode::~BSPNode()
+{
+ delete polygon;
+ delete backpolygon;
+ delete separatorplane;
+ delete boundingbox;
+ delete frontsubtree;
+ delete backsubtree;
+}
+
+
+// traverse bsp tree (preorder) and number nodes as encountered ---------------
+//
+void BSPNode::NumberBSPNodes( int& curno )
+{
+ // store nodenumber
+ nodenumber = ++curno;
+
+ // assign node numbers to all polygons contained in splitter plane
+ static Polygon *polylist;
+ for ( polylist = polygon ? polygon->getNext() : NULL; polylist; polylist = polylist->getNext() ) {
+ // only increment numbering, numbers don't get stored in polygons!
+ ++curno;
+ }
+ for ( polylist = backpolygon; polylist; polylist = polylist->getNext() ) {
+ // only increment numbering, numbers don't get stored in polygons!
+ ++curno;
+ }
+
+ // do numbering recursively for front- and backsubtree
+ if ( frontsubtree ) frontsubtree->NumberBSPNodes( curno );
+ if ( backsubtree ) backsubtree->NumberBSPNodes( curno );
+}
+
+
+// sum number of vertices of all polygon in tree ------------------------------
+//
+void BSPNode::SumVertexNums( int& vtxnum )
+{
+ // sum number of vertices of polygons contained in this plane
+ static Polygon *polylist;
+ for ( polylist = polygon; polylist; polylist = polylist->getNext() )
+ vtxnum += polylist->getNumVertices();
+ for ( polylist = backpolygon; polylist; polylist = polylist->getNext() )
+ vtxnum += polylist->getNumVertices();
+
+ // do sum recursively for front- and backsubtree
+ if ( frontsubtree ) frontsubtree->SumVertexNums( vtxnum );
+ if ( backsubtree ) backsubtree->SumVertexNums( vtxnum );
+}
+
+
+// traverse entire tree and correct relative polygon info to new base values --
+//
+void BSPNode::CorrectPolygonBases( BspObject *newbaseobj, int vertexindxbase, int faceidbase, int polygonidbase )
+{
+ static Polygon *polylist;
+ for ( polylist = polygon; polylist; polylist = polylist->getNext() )
+ polylist->CorrectBase( newbaseobj, vertexindxbase, faceidbase, polygonidbase );
+ for ( polylist = backpolygon; polylist; polylist = polylist->getNext() )
+ polylist->CorrectBase( newbaseobj, vertexindxbase, faceidbase, polygonidbase );
+
+ if ( frontsubtree ) frontsubtree->CorrectPolygonBases( newbaseobj, vertexindxbase, faceidbase, polygonidbase );
+ if ( backsubtree ) backsubtree->CorrectPolygonBases( newbaseobj, vertexindxbase, faceidbase, polygonidbase );
+}
+
+
+// traverse entire tree and correct relative polygon info to new base values --
+//
+void BSPNode::CorrectPolygonBasesByTable( BspObject *newbaseobj, int *vtxindxmap, int faceidbase, int polygonidbase )
+{
+ static Polygon *polylist;
+ for ( polylist = polygon; polylist; polylist = polylist->getNext() )
+ polylist->CorrectBaseByTable( newbaseobj, vtxindxmap, faceidbase, polygonidbase );
+ for ( polylist = backpolygon; polylist; polylist = polylist->getNext() )
+ polylist->CorrectBaseByTable( newbaseobj, vtxindxmap, faceidbase, polygonidbase );
+
+ if ( frontsubtree ) frontsubtree->CorrectPolygonBasesByTable( newbaseobj, vtxindxmap, faceidbase, polygonidbase );
+ if ( backsubtree ) backsubtree->CorrectPolygonBasesByTable( newbaseobj, vtxindxmap, faceidbase, polygonidbase );
+}
+
+
+// write bsp tree structure to output file (preorder traversal) ---------------
+//
+void BSPNode::WriteBSPTree( FILE *fp )
+{
+ static int lnodnum, rnodnum, cnodnum, bnodnum;
+ static int curnodnum;
+ static Polygon *polylist;
+
+ lnodnum = frontsubtree ? frontsubtree->nodenumber : 0;
+ rnodnum = backsubtree ? backsubtree->nodenumber : 0;
+
+ if ( polygon != NULL ) {
+ cnodnum = polygon->getNext() ? nodenumber + 1 : 0;
+ bnodnum = backpolygon ? nodenumber + polygon->getNumPolygons() : 0;
+ } else {
+ cnodnum = 0;
+ bnodnum = 0;
+ }
+
+ if ( outputformat == OUTPUT_OLD_STYLE ) {
+
+ if ( polygon != NULL ) {
+ // print head node
+ fprintf( fp, "%d: %d |%d|%d|%d-%d|\n",
+ nodenumber, polygon->getId() + 1, cnodnum, bnodnum, lnodnum, rnodnum );
+
+ // print list of contained nodes (frontfacing)
+ curnodnum = cnodnum;
+ polylist = polygon;
+ while ( ( polylist = polylist->getNext() ) != NULL ) {
+ cnodnum = polylist->getNext() ? ( curnodnum + 1 ) : 0;
+ fprintf( fp, "%d: %d |%d|0|\n", curnodnum++, polylist->getId() + 1, cnodnum );
+ }
+
+ // print list of contained nodes (backfacing)
+ curnodnum = bnodnum;
+ for ( polylist = backpolygon; polylist; polylist = polylist->getNext() ) {
+ bnodnum = polylist->getNext() ? ( curnodnum + 1 ) : 0;
+ fprintf( fp, "%d: %d |0|%d|\n", curnodnum++, polylist->getId() + 1, bnodnum );
+ }
+ } else {
+ //NOTE:
+ // nodes not containing polygons are not supported
+ // by the old ouput format!
+ fprintf( fp, "no polygon contained in node %d.", nodenumber );
+ }
+
+ } else {
+
+ // print head node
+ fprintf( fp, "%d: ", nodenumber );
+ if ( polygon != NULL )
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_polygon_str, polygon->getId() + 1 );
+ if ( cnodnum != 0 )
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_frontlist_str, cnodnum );
+ if ( bnodnum != 0 )
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_backlist_str, bnodnum );
+ if ( lnodnum != 0 )
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_fronttree_str, lnodnum );
+ if ( rnodnum != 0 )
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_backtree_str, rnodnum );
+ if ( separatorplane != NULL ) {
+ Vector3 normal = separatorplane->getPlaneNormal();
+ fprintf( fp, "%s %f %f %f %f ", BspFormat::_bspspec_plane_str,
+ normal.getX(), normal.getY(), normal.getZ(),
+ separatorplane->getPlaneOffset() );
+ }
+ if ( boundingbox != NULL ) {
+ Vertex3 minvert = boundingbox->getMinVertex();
+ Vertex3 maxvert = boundingbox->getMaxVertex();
+ fprintf( fp, "%s %f %f %f %f %f %f ", BspFormat::_bspspec_boundingbox_str,
+ minvert.getX(), minvert.getY(), minvert.getZ(),
+ maxvert.getX(), maxvert.getY(), maxvert.getZ() );
+ }
+ fprintf( fp, "\n" );
+
+ // print list of contained nodes (frontfacing)
+ if ( polygon != NULL ) {
+ curnodnum = cnodnum;
+ polylist = polygon;
+ while ( ( polylist = polylist->getNext() ) != NULL ) {
+ fprintf( fp, "%d: ", curnodnum );
+ cnodnum = polylist->getNext() ? ++curnodnum : 0;
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_polygon_str, polylist->getId() + 1 );
+ if ( cnodnum != 0 )
+ fprintf( fp, "%s %d", BspFormat::_bspspec_frontlist_str, cnodnum );
+ fprintf( fp, "\n" );
+ }
+ }
+
+ // print list of contained nodes (backfacing)
+ curnodnum = bnodnum;
+ for ( polylist = backpolygon; polylist; polylist = polylist->getNext() ) {
+ fprintf( fp, "%d: ", curnodnum );
+ bnodnum = polylist->getNext() ? ++curnodnum : 0;
+ fprintf( fp, "%s %d ", BspFormat::_bspspec_polygon_str, polylist->getId() + 1 );
+ if ( bnodnum != 0 )
+ fprintf( fp, "%s %d", BspFormat::_bspspec_backlist_str, bnodnum );
+ fprintf( fp, "\n" );
+ }
+
+ }
+
+ // write out front- and backsubtree recursively
+ if ( frontsubtree ) frontsubtree->WriteBSPTree( fp );
+ if ( backsubtree ) backsubtree->WriteBSPTree( fp );
+}
+
+
+// fetch pointer to polygon with given number contained in bsp tree -----------
+//
+Polygon *BSPNode::FetchBSPPolygon( int polyno )
+{
+ // search local node and contained list (frontfacing)
+ static Polygon *clist;
+ for ( clist = polygon; clist; clist = clist->getNext() ) {
+ if ( clist->getId() == polyno )
+ return clist;
+ }
+
+ // search list of contained backfacing polygons
+ for ( clist = backpolygon; clist; clist = clist->getNext() ) {
+ if ( clist->getId() == polyno )
+ return clist;
+ }
+
+ Polygon *search = NULL;
+
+ if ( frontsubtree )
+ search = frontsubtree->FetchBSPPolygon( polyno );
+ if ( ( search == NULL ) && backsubtree )
+ search = backsubtree->FetchBSPPolygon( polyno );
+
+ return search;
+}
+
+
+// fetch all polygon numbers contained in specific face -----------------------
+//
+void BSPNode::FetchFacePolygons( int faceno, PolygonList& facepolylist )
+{
+ // search local node and contained list (frontfacing)
+ static Polygon *clist;
+ for ( clist = polygon; clist; clist = clist->getNext() ) {
+ if ( clist->getFaceId() == faceno )
+ facepolylist.InsertPolygon( new Polygon( NULL, clist->getId(), clist->getFaceId() ) );
+ }
+
+ // search list of contained backfacing polygons
+ for ( clist = backpolygon; clist; clist = clist->getNext() ) {
+ if ( clist->getFaceId() == faceno )
+ facepolylist.InsertPolygon( new Polygon( NULL, clist->getId(), clist->getFaceId() ) );
+ }
+
+ // check children (subtrees)
+ if ( frontsubtree ) frontsubtree->FetchFacePolygons( faceno, facepolylist );
+ if ( backsubtree ) backsubtree->FetchFacePolygons( faceno, facepolylist );
+}
+
+
+// check edges for contained vertices and insert them as trace vertices -------
+//
+void BSPNode::CheckEdges()
+{
+ // check list of frontfacing polygons
+ if ( polygon ) polygon->CheckEdges();
+
+ // check list of backfacing polygons
+ if ( backpolygon ) backpolygon->CheckEdges();
+
+ // check children (subtrees)
+ if ( frontsubtree ) frontsubtree->CheckEdges();
+ if ( backsubtree ) backsubtree->CheckEdges();
+}
+
+
+// grow this node's bounding box by another node's ----------------------------
+//
+void BSPNode::GrowBoundingBox( BSPNode *othernode )
+{
+ if ( othernode != NULL ) {
+ // ensure other node has a bounding box (calculate if not)
+ if ( othernode->boundingbox == NULL )
+ othernode->CalcBoundingBoxes();
+ static BoundingBox *otherbox;
+ otherbox = othernode->boundingbox;
+
+ if ( boundingbox == NULL ) {
+ // if this node has no bounding box copy other node's
+ boundingbox = new BoundingBox( otherbox->getMinVertex(), otherbox->getMaxVertex() );
+ } else {
+ // merge the two bounding boxes
+ boundingbox->GrowBoundingBox( otherbox );
+ }
+ }
+}
+
+
+// calculate axial bounding box for this node and all children ----------------
+//
+void BSPNode::CalcBoundingBoxes()
+{
+ if ( boundingbox == NULL ) {
+
+ // if polygon(s) contained in this node calculate their bounding box
+ if ( polygon != NULL ) {
+ polygon->CalcBoundingBox( boundingbox );
+ if ( backpolygon != NULL ) {
+ static BoundingBox *backbox;
+ backpolygon->CalcBoundingBox( backbox );
+ boundingbox->GrowBoundingBox( backbox );
+ delete backbox;
+ }
+ }
+
+ // grow local bounding box by children's
+ GrowBoundingBox( frontsubtree );
+ GrowBoundingBox( backsubtree );
+ }
+}
+
+
+// calculate separator planes from polygons for entire bsp tree ---------------
+//
+void BSPNode::CalcSeparatorPlanes()
+{
+ if ( ( separatorplane == NULL ) && ( polygon != NULL ) ) {
+ separatorplane = new Plane( polygon->getFirstVertex(),
+ polygon->getSecondVertex(),
+ polygon->getThirdVertex() );
+ }
+
+ // check children (subtrees)
+ if ( frontsubtree ) frontsubtree->CalcSeparatorPlanes();
+ if ( backsubtree ) backsubtree->CalcSeparatorPlanes();
+}
+
+
+// format to use when writing bsp nodes to files ------------------------------
+//
+int BSPNode::outputformat = BSPNode::OUTPUT_KEY_VALUE_STYLE;
+
+
+// construct BSPNodeFlat ------------------------------------------------------
+//
+BSPNodeFlat::BSPNodeFlat( int front, int back, Polygon *poly, int clist, int blist, Plane *sep, BoundingBox *box, int num )
+{
+ frontsubtreeindx = front;
+ backsubtreeindx = back;
+ polygon = poly;
+ containedlistindx = clist;
+ backlistindx = blist;
+ separatorplane = sep;
+ boundingbox = box;
+ nodenumber = num;
+}
+
+
+// init BSPNodeFlat members ---------------------------------------------------
+//
+void BSPNodeFlat::InitNode( int front, int back, Polygon *poly, int clist, int blist, Plane *sep, BoundingBox *box, int num )
+{
+ frontsubtreeindx = front;
+ backsubtreeindx = back;
+ polygon = poly;
+ containedlistindx = clist;
+ backlistindx = blist;
+ separatorplane = sep;
+ boundingbox = box;
+ nodenumber = num;
+}
+
+
+// apply scale factor to separator plane and bounding box if attached ---------
+//
+void BSPNodeFlat::ApplyScaleFactor( double sfac )
+{
+ if ( separatorplane != NULL )
+ separatorplane->ApplyScaleFactor( sfac );
+ if ( boundingbox != NULL )
+ boundingbox->ApplyScaleFactor( sfac );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BSPNode.h b/tool_src/BspLib/BSPNode.h
new file mode 100644
index 0000000..0dba2ef
--- /dev/null
+++ b/tool_src/BspLib/BSPNode.h
@@ -0,0 +1,132 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BSPNode.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPNODE_H_
+#define _BSPNODE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "PolygonList.h"
+#include "Plane.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+class BoundingBox;
+class BspObject;
+
+
+// node of bsp tree -----------------------------------------------------------
+//
+class BSPNode {
+
+public:
+
+ // output formats
+ enum {
+ OUTPUT_OLD_STYLE,
+ OUTPUT_KEY_VALUE_STYLE
+ };
+
+public:
+ BSPNode( BSPNode *front = NULL, BSPNode *back = NULL,
+ Polygon *poly = NULL, Polygon *backpoly = NULL,
+ Plane *sep = NULL, BoundingBox *box = NULL, int num = -1 );
+ ~BSPNode();
+
+public:
+ void NumberBSPNodes( int& curno );
+ void SumVertexNums( int& vtxnum );
+ void CorrectPolygonBases( BspObject *newbaseobj, int vertexindxbase, int faceidbase, int polygonidbase );
+ void CorrectPolygonBasesByTable( BspObject *newbaseobj, int *vtxindxmap, int faceidbase, int polygonidbase );
+ void WriteBSPTree( FILE *fp );
+ void CheckEdges();
+ void FetchFacePolygons( int facno, PolygonList& facepolylist );
+ Polygon* FetchBSPPolygon( int polyno );
+ void CalcBoundingBoxes();
+ void CalcSeparatorPlanes();
+
+ int getNodeNumber() const { return nodenumber; }
+ Polygon* getPolygon() { return polygon; }
+ Polygon* getBackPolygon() { return backpolygon; }
+ BSPNode* getFrontSubtree() const { return frontsubtree; }
+ BSPNode* getBackSubtree() const { return backsubtree; }
+
+ Plane* getSeparatorPlane() { return separatorplane; }
+ void setSeparatorPlane( Plane *sep ) { separatorplane = sep; }
+
+ BoundingBox*getBoundingBox() { return boundingbox; }
+ void setBoundingBox( BoundingBox *box ) { boundingbox = box; }
+
+private:
+ void GrowBoundingBox( BSPNode *othernode );
+
+public:
+ static int getOutputFormat() { return outputformat; }
+ static void setOutputFormat( int format ) { outputformat = format; }
+
+private:
+ static int outputformat; // format used to write bsp nodes to files
+
+private:
+ int nodenumber; // node id
+ Polygon* polygon; // list of frontfacing polygons in splitting plane
+ Polygon* backpolygon; // list of backfacing polygons in splitting plane
+ Plane* separatorplane; // plane if node is only separator (no polygons!)
+ BoundingBox*boundingbox; // bounding box containing node and all children
+ BSPNode* frontsubtree; // tree partitioning front halfspace
+ BSPNode* backsubtree; // tree partitioning back halfspace
+};
+
+
+// node of flat bsp tree ------------------------------------------------------
+//
+class BSPNodeFlat {
+
+public:
+ BSPNodeFlat( int front = 0, int back = 0,
+ Polygon *poly = NULL, int clist = 0, int blist = 0,
+ Plane *sep = NULL, BoundingBox *box = NULL, int num = -1 );
+ ~BSPNodeFlat() { /* don't delete polygon, separatorplane, and boundingbox!! */ }
+
+public:
+ void InitNode( int front, int back, Polygon *poly, int clist, int blist,
+ Plane *sep = NULL, BoundingBox *box = NULL, int num = -1 );
+
+ void ApplyScaleFactor( double sfac );
+
+ int getNodeNumber() const { return nodenumber; }
+ Polygon* getPolygon() { return polygon; }
+ int getContainedList() const { return containedlistindx; }
+ int getBackList() const { return backlistindx; }
+ int getFrontSubTree() const { return frontsubtreeindx; }
+ int getBackSubTree() const { return backsubtreeindx; }
+
+ Plane* getSeparatorPlane() { return separatorplane; }
+ void setSeparatorPlane( Plane *sep ) { separatorplane = sep; }
+
+ BoundingBox*getBoundingBox() { return boundingbox; }
+ void setBoundingBox( BoundingBox *box ) { boundingbox = box; }
+
+private:
+ int nodenumber; // node id (may be different than array index!!)
+ Polygon* polygon; // this node's polygon
+ Plane* separatorplane; // plane if node is only separator (no polygons!)
+ BoundingBox*boundingbox; // bounding box containing node and all children
+ int containedlistindx; // contained frontfacing polygons
+ int backlistindx; // contained backfacing polygons
+ int frontsubtreeindx; // front subtree
+ int backsubtreeindx; // back subtree
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPNODE_H_
+
diff --git a/tool_src/BspLib/BSPTree.cpp b/tool_src/BspLib/BSPTree.cpp
new file mode 100644
index 0000000..5c94dbe
--- /dev/null
+++ b/tool_src/BspLib/BSPTree.cpp
@@ -0,0 +1,121 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BSPTree.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BSPTree.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+#define BLOCK_SIZE 4096
+
+
+// append new node to flat bsp tree -------------------------------------------
+//
+BSPNodeFlat *BSPTreeFlatRep::AppendNode( int front, int back, Polygon *poly, int clist, int blist )
+{
+ // expand storage area (array) if no space available
+ if ( nodestorage - numnodes == 0 ) {
+ BSPNodeFlat *newroot = new BSPNodeFlat[ nodestorage + BLOCK_SIZE ];
+ if ( root != NULL ) {
+ memcpy( newroot, root, nodestorage * sizeof( BSPNodeFlat ) );
+ delete[] root;
+ }
+ root = newroot;
+ nodestorage += BLOCK_SIZE;
+ }
+ // init new node and return its address
+ root[ numnodes ].InitNode( front, back, poly, clist, blist );
+ return root + numnodes++;
+}
+
+
+// fetch node per id (node number) --------------------------------------------
+//
+BSPNodeFlat *BSPTreeFlatRep::FetchNodePerId( int id )
+{
+ // id has to be greater than 0 since 0 means empty halfspace
+ return ( ( id > 0 ) && ( id <= numnodes ) ) ? ( root + id - 1 ) : NULL;
+}
+
+
+// apply scale factor to separator planes and bounding boxes of all nodes -----
+//
+void BSPTreeFlatRep::ApplyScaleFactor( double sfac )
+{
+ BSPNodeFlat *scan = root;
+ for ( int i = 0; i < numnodes; i++, scan++ )
+ scan->ApplyScaleFactor( sfac );
+}
+
+
+// build pointer-based bsp tree from flat representation ----------------------
+//
+BSPNode *BSPTreeFlatRep::BuildBSPTree( int nodenum )
+{
+ if ( nodenum == 0 )
+ return NULL;
+
+ BSPNodeFlat *node = FetchNodePerId( nodenum );
+ if ( node == NULL )
+ return NULL;
+
+ // get node's polygon
+ Polygon *poly = node->getPolygon();
+
+ // append contained list to polygon (frontfacing polygons)
+ static int containedindx;
+ static Polygon *precpoly;
+ containedindx = node->getContainedList();
+ precpoly = poly;
+ while ( containedindx > 0 ) {
+ static BSPNodeFlat *cnode;
+ static Polygon *cpoly;
+ cnode = FetchNodePerId( containedindx );
+ cpoly = cnode ? cnode->getPolygon() : NULL;
+ containedindx = cnode ? cnode->getContainedList() : 0;
+ precpoly->setNext( cpoly );
+ precpoly = cpoly;
+ }
+ if ( precpoly ) {
+ // detach original polygon list
+ precpoly->setNext( NULL );
+ }
+
+ // build list of backfacing polygons (backlist)
+ Polygon *backlist = NULL;
+ containedindx = node->getBackList();
+ precpoly = NULL;
+ while ( containedindx > 0 ) {
+ static BSPNodeFlat *cnode;
+ static Polygon *cpoly;
+ cnode = FetchNodePerId( containedindx );
+ cpoly = cnode ? cnode->getPolygon() : NULL;
+ containedindx = cnode ? cnode->getBackList() : 0;
+ if ( precpoly == NULL)
+ backlist = cpoly;
+ else
+ precpoly->setNext( cpoly );
+ precpoly = cpoly;
+ }
+ if ( precpoly ) {
+ // detach original polygon list
+ precpoly->setNext( NULL );
+ }
+
+ // recursively build front- and back-subtree
+ BSPNode *front = BuildBSPTree( node->getFrontSubTree() );
+ BSPNode *back = BuildBSPTree( node->getBackSubTree() );
+
+ return new BSPNode( front, back, poly, backlist, node->getSeparatorPlane(), node->getBoundingBox() );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BSPTree.h b/tool_src/BspLib/BSPTree.h
new file mode 100644
index 0000000..b96a93c
--- /dev/null
+++ b/tool_src/BspLib/BSPTree.h
@@ -0,0 +1,182 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BSPTree.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPTREE_H_
+#define _BSPTREE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BSPNode.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// bsp tree; basically pointer to root node (representation class) ------------
+//
+class BSPTreeRep {
+
+ friend class BSPTree;
+
+private:
+ BSPTreeRep() : ref_count( 0 ) { root = NULL; }
+ ~BSPTreeRep() { delete root; }
+
+ BSPNode* InitTree( BSPNode *rootnode );
+ BSPNode* getRoot() { return root; }
+
+ void InvalidateTree();
+
+ int TreeEmpty() const { return ( root == NULL ); }
+
+private:
+ int ref_count;
+ BSPNode* root;
+};
+
+// init with entire tree of BSPNode objects -----------------------------------
+inline BSPNode *BSPTreeRep::InitTree( BSPNode *rootnode )
+{
+ delete root;
+ return ( root = rootnode );
+}
+
+// set root to null without deleting tree first -------------------------------
+inline void BSPTreeRep::InvalidateTree()
+{
+ root = NULL;
+}
+
+
+// bsp tree; basically pointer to root node (handle class) --------------------
+//
+class BSPTree {
+
+public:
+ BSPTree() { rep = new BSPTreeRep; rep->ref_count = 1; }
+ ~BSPTree() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ BSPTree( const BSPTree& copyobj );
+ BSPTree& operator =( const BSPTree& copyobj );
+
+ // pass most operations through to BSPNode
+ BSPNode* operator->() { return rep->getRoot(); }
+
+ BSPNode* InitTree( BSPNode *rootnode ) { return rep->InitTree( rootnode ); }
+ BSPNode* getRoot() { return rep->getRoot(); }
+
+ void InvalidateTree() { rep->InvalidateTree(); }
+
+ int TreeEmpty() const { return rep->TreeEmpty(); }
+
+private:
+ BSPTreeRep* rep;
+};
+
+// copy constructor -----------------------------------------------------------
+inline BSPTree::BSPTree( const BSPTree& copyobj )
+{
+ rep = copyobj.rep;
+ rep->ref_count++;
+}
+
+// assignment operator --------------------------------------------------------
+inline BSPTree& BSPTree::operator =( const BSPTree& copyobj )
+{
+ if ( &copyobj != this ) {
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep;
+ rep->ref_count++;
+ }
+ return *this;
+}
+
+
+// flat bsp tree; basically pointer to array (representation class) -----------
+//
+class BSPTreeFlatRep {
+
+ friend class BSPTreeFlat;
+
+private:
+ BSPTreeFlatRep() : ref_count( 0 ) { root = NULL; numnodes = 0; nodestorage = 0; }
+ ~BSPTreeFlatRep() { delete[] root; }
+
+ BSPNodeFlat* AppendNode( int front, int back, Polygon *poly, int clist, int blist );
+ BSPNodeFlat* FetchNodePerId( int id );
+ BSPNode* BuildBSPTree( int nodenum );
+ BSPNodeFlat* getRoot() { return root; }
+
+ int TreeEmpty() const { return ( root == NULL ); }
+ int getNumNodes() const { return numnodes; }
+
+ void ApplyScaleFactor( double sfac );
+ void DestroyTree() { delete[] root; root = NULL; numnodes = 0; nodestorage = 0; }
+
+private:
+ int ref_count;
+ int numnodes;
+ int nodestorage;
+ BSPNodeFlat* root;
+};
+
+
+// flat bsp tree; basically pointer to array (handle class) -------------------
+//
+class BSPTreeFlat {
+
+public:
+ BSPTreeFlat() { rep = new BSPTreeFlatRep; rep->ref_count = 1; }
+ ~BSPTreeFlat() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ BSPTreeFlat( const BSPTreeFlat& copyobj );
+ BSPTreeFlat& operator =( const BSPTreeFlat& copyobj );
+
+ BSPNodeFlat* AppendNode( int front, int back, Polygon *poly, int clist, int blist )
+ { return rep->AppendNode( front, back, poly, clist, blist ); }
+ BSPNodeFlat* FetchNodePerId( int id ) { return rep->FetchNodePerId( id ); }
+ BSPNode* BuildBSPTree( int nodenum ) { return rep->BuildBSPTree( nodenum ); }
+ BSPNodeFlat* getRoot() { return rep->getRoot(); }
+
+ int TreeEmpty() const { return rep->TreeEmpty(); }
+ int getNumNodes() const { return rep->getNumNodes(); }
+
+ void ApplyScaleFactor( double sfac ) { rep->ApplyScaleFactor( sfac ); }
+ void DestroyTree() { rep->DestroyTree(); }
+
+private:
+ BSPTreeFlatRep* rep;
+};
+
+// copy constructor -----------------------------------------------------------
+inline BSPTreeFlat::BSPTreeFlat( const BSPTreeFlat& copyobj )
+{
+ rep = copyobj.rep;
+ rep->ref_count++;
+}
+
+// assignment operator --------------------------------------------------------
+inline BSPTreeFlat& BSPTreeFlat::operator =( const BSPTreeFlat& copyobj )
+{
+ if ( &copyobj != this ) {
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep;
+ rep->ref_count++;
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPTREE_H_
+
diff --git a/tool_src/BspLib/BoundingBox.cpp b/tool_src/BspLib/BoundingBox.cpp
new file mode 100644
index 0000000..04008c2
--- /dev/null
+++ b/tool_src/BspLib/BoundingBox.cpp
@@ -0,0 +1,223 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BoundingBox.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "BoundingBox.h"
+#include "ObjectBSPNode.h"
+#include "Plane.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// apply scale factor to bounding box -----------------------------------------
+//
+void BoundingBox::ApplyScaleFactor( double sfac )
+{
+ //NOTE:
+ // this will be needed if the attached object is scaled.
+ // the scale factor is applied to the space containing the
+ // bounding box, i.e. its midpoint will move.
+
+ minvertex.setX( minvertex.getX() * sfac );
+ minvertex.setY( minvertex.getY() * sfac );
+ minvertex.setZ( minvertex.getZ() * sfac );
+
+ maxvertex.setX( maxvertex.getX() * sfac );
+ maxvertex.setY( maxvertex.getY() * sfac );
+ maxvertex.setZ( maxvertex.getZ() * sfac );
+}
+
+
+// grow this bounding box by another one (maximum/minimum merge) --------------
+//
+void BoundingBox::GrowBoundingBox( BoundingBox *otherbox )
+{
+ if ( otherbox != NULL ) {
+ if ( otherbox->minvertex.getX() < minvertex.getX() )
+ minvertex.setX( otherbox->minvertex.getX() );
+ if ( otherbox->minvertex.getY() < minvertex.getY() )
+ minvertex.setY( otherbox->minvertex.getY() );
+ if ( otherbox->minvertex.getZ() < minvertex.getZ() )
+ minvertex.setZ( otherbox->minvertex.getZ() );
+
+ if ( otherbox->maxvertex.getX() > maxvertex.getX() )
+ maxvertex.setX( otherbox->maxvertex.getX() );
+ if ( otherbox->maxvertex.getY() > maxvertex.getY() )
+ maxvertex.setY( otherbox->maxvertex.getY() );
+ if ( otherbox->maxvertex.getZ() > maxvertex.getZ() )
+ maxvertex.setZ( otherbox->maxvertex.getZ() );
+ }
+}
+
+
+// fill in bounding box as union of entire list -------------------------------
+//
+void BoundingBox::BoundingBoxListUnion( BoundingBox& unionbox )
+{
+ // init union box
+ delete unionbox.nextbox;
+ unionbox.nextbox = NULL;
+ unionbox.containedobject = NULL;
+ unionbox.minvertex = minvertex;
+ unionbox.maxvertex = maxvertex;
+
+ // build union of entire list
+ for ( BoundingBox *curbox = nextbox; curbox; curbox = curbox->nextbox )
+ unionbox.GrowBoundingBox( curbox );
+}
+
+
+// partition list of bounding boxing boxes and build tree structure -----------
+//
+ObjectBSPNode *BoundingBox::PartitionSpace()
+{
+ //NOTE:
+ // this function alters the link fields of the objects attached
+ // to bounding boxes. therefore, the original linked list of
+ // objects is invalid after this function! the objects themselves
+ // are only accessible via tree nodes afterwards.
+
+ //NOTE:
+ // analogously to polygon bsp trees where the polygon list is dissolved
+ // in the process of bsp compilation, the list of bounding boxes is
+ // completely dissolved by this function! that is, the bounding box
+ // for which PartitionSpace() has been invoked should not be accessed
+ // directly anymore. all bounding boxes can then be accessed via the
+ // generated object-bsp-tree!
+
+ // only one box in this subspace?
+ if ( nextbox == NULL ) {
+ // unlink tail of object list
+ containedobject->next = NULL;
+ // create ObjectBSPNode for this box (leaf!)
+ return new ObjectBSPNode( NULL, NULL, NULL, this );
+ }
+
+ // select a separating plane
+ Vector3 separatornormal( 1.0, 0.0, 0.0 );
+ double separatoroffset = maxvertex.getX();
+ int currentboundary = 0;
+ Plane *separator = new Plane( separatornormal, separatoroffset );
+ BoundingBox *currentbox = this;
+ // scan all bounding boxes to find a suitable separating plane
+ for ( currentbox = this; ; ) {
+
+ // check if plane separates bounding boxes cleanly
+ int cleanseparation = 1;
+ int membersofpos = 0;
+ int membersofneg = 0;
+ for ( BoundingBox *scan = this; scan; scan = scan->getNext() ) {
+ if ( !separator->PointInNegativeHalfspace( scan->getMinVertex() ) &&
+ !separator->PointInNegativeHalfspace( scan->getMaxVertex() ) ) {
+ membersofpos++;
+ } else if ( !separator->PointInPositiveHalfspace( scan->getMinVertex() ) &&
+ !separator->PointInPositiveHalfspace( scan->getMaxVertex() ) ) {
+ membersofneg++;
+ } else {
+ cleanseparation = 0;
+ break;
+ }
+ }
+ //NOTE:
+ // both halfspaces have to contain bounding boxes; separation of vacant
+ // space from inhabited space just makes the tree unnecessarily large.
+ // this does not influence if there is a clean separating plane or not!
+ if ( ( membersofpos > 0 ) && ( membersofneg > 0 ) && cleanseparation )
+ break;
+
+ // try next boundary plane
+ currentboundary = ( currentboundary + 1 ) % 6;
+ if ( currentboundary == 0 )
+ currentbox = currentbox->getNext();
+
+ if ( currentbox != NULL ) {
+ switch ( currentboundary ) {
+ case 0:
+ separatornormal = Vector3( 1.0, 0.0, 0.0 );
+ separatoroffset = currentbox->maxvertex.getX();
+ break;
+ case 1:
+ separatornormal = Vector3( 0.0, 1.0, 0.0 );
+ separatoroffset = currentbox->maxvertex.getY();
+ break;
+ case 2:
+ separatornormal = Vector3( 0.0, 0.0, 1.0 );
+ separatoroffset = currentbox->maxvertex.getZ();
+ break;
+ case 3:
+ separatornormal = Vector3( -1.0, 0.0, 0.0 );
+ separatoroffset = -currentbox->minvertex.getX();
+ break;
+ case 4:
+ separatornormal = Vector3( 0.0, -1.0, 0.0 );
+ separatoroffset = -currentbox->minvertex.getY();
+ break;
+ case 5:
+ separatornormal = Vector3( 0.0, 0.0, -1.0 );
+ separatoroffset = -currentbox->minvertex.getZ();
+ break;
+ }
+ separator->setPlaneNormal( separatornormal );
+ separator->setPlaneOffset( separatoroffset );
+ } else {
+ break;
+ }
+ }
+
+ BoundingBox *frontsubspace = NULL;
+ BoundingBox *backsubspace = NULL;
+
+ if ( currentbox != NULL ) {
+ // partition space into two halfspaces (walk list of bounding boxes)
+ for ( currentbox = this; currentbox; ) {
+ if ( !separator->PointInNegativeHalfspace( currentbox->getMinVertex() ) &&
+ !separator->PointInNegativeHalfspace( currentbox->getMaxVertex() ) ) {
+ // box contained in positive halfspace
+ BoundingBox *tmpbox = currentbox->getNext();
+ currentbox->nextbox = frontsubspace;
+ frontsubspace = currentbox;
+ currentbox = tmpbox;
+ } else {
+ // box contained in negative halfspace
+ BoundingBox *tmpbox = currentbox->getNext();
+ currentbox->nextbox = backsubspace;
+ backsubspace = currentbox;
+ currentbox = tmpbox;
+ }
+ }
+ } else {
+ // no suitable separating plane found: create list of unseparable objects
+ for ( currentbox = this; currentbox; currentbox = currentbox->getNext() ) {
+ currentbox->containedobject->next =
+ currentbox->getNext() ? currentbox->getNext()->containedobject : NULL;
+ }
+ // delete legacy bounding boxes
+ delete nextbox;
+ nextbox = NULL;
+ // create ObjectBSPNode for this box (leaf!)
+ return new ObjectBSPNode( NULL, NULL, NULL, this );
+
+ //NOTE:
+ // if bounding boxes cannot be separated cleanly, their corresponding objects
+ // are inserted into a linear list attached to a single bounding box. this
+ // bounding box, however, encompasses only the head of this list!
+ // for bsp compilation, the objects in these lists have to be explicitly merged
+ // into a single object. this is not done automatically!
+ // currently, only ObjectBSPNode::CreateObjectList() merges these objects.
+ }
+
+ // allocate new root; partition halfspaces recursively and return root
+ ObjectBSPNode *front = frontsubspace ? frontsubspace->PartitionSpace() : NULL;
+ ObjectBSPNode *back = backsubspace ? backsubspace->PartitionSpace() : NULL;
+ return new ObjectBSPNode( front, back, separator, NULL );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BoundingBox.h b/tool_src/BspLib/BoundingBox.h
new file mode 100644
index 0000000..417d854
--- /dev/null
+++ b/tool_src/BspLib/BoundingBox.h
@@ -0,0 +1,72 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BoundingBox.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BOUNDINGBOX_H_
+#define _BOUNDINGBOX_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// axial bounding box; can be part of singly linked list ----------------------
+//
+class BoundingBox {
+
+ friend class ObjectBSPNode;
+
+public:
+ BoundingBox() { containedobject = NULL; nextbox = NULL; }
+ BoundingBox( BspObject *cobj, BoundingBox *next = NULL );
+ BoundingBox( const Vertex3& minvert, const Vertex3& maxvert, BoundingBox *next = NULL );
+ ~BoundingBox() { delete nextbox; }
+
+ void ApplyScaleFactor( double sfac );
+ void GrowBoundingBox( BoundingBox *otherbox );
+ void BoundingBoxListUnion( BoundingBox& unionbox );
+ class ObjectBSPNode* PartitionSpace();
+
+ Vertex3 getMinVertex() const { return minvertex; }
+ Vertex3 getMaxVertex() const { return maxvertex; }
+ BspObject* getContainedObject() const { return containedobject; }
+ BoundingBox* getNext() const { return nextbox; }
+
+private:
+ Vertex3 minvertex;
+ Vertex3 maxvertex;
+ BspObject* containedobject;
+ BoundingBox* nextbox;
+};
+
+// construct bounding box by calculating its extents --------------------------
+inline BoundingBox::BoundingBox( BspObject *cobj, BoundingBox *next )
+{
+ if ( ( containedobject = cobj ) != NULL ) {
+ cobj->CalcBoundingBox( minvertex, maxvertex );
+ }
+ nextbox = next;
+}
+
+// construct bounding box directly --------------------------------------------
+inline BoundingBox::BoundingBox( const Vertex3& minvert, const Vertex3& maxvert, BoundingBox *next )
+{
+ minvertex = minvert;
+ maxvertex = maxvert;
+ containedobject = NULL;
+ nextbox = next;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BOUNDINGBOX_H_
+
diff --git a/tool_src/BspLib/BspFormat.cpp b/tool_src/BspLib/BspFormat.cpp
new file mode 100644
index 0000000..a358339
--- /dev/null
+++ b/tool_src/BspLib/BspFormat.cpp
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BspFormat.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// get index to section id specified as string (this function is static!) -----
+//
+int BspFormat::GetSectionId( char *section_name )
+{
+ int sectionid = SingleFormat::GetSectionId( section_name );
+ if ( sectionid == _nil ) {
+ for ( int i = 0; i < _num_bsp_sections - _num_single_sections; i++ )
+ if ( stricmp( section_name, section_strings[ i ] ) == 0 )
+ return section_ids[ i ];
+ }
+ return sectionid;
+}
+
+
+// get name of section specified via id (this function is static!) ------------
+//
+const char *BspFormat::GetSectionName( int section_id )
+{
+ const char *sectionname = SingleFormat::GetSectionName( section_id );
+ if ( sectionname == NULL ) {
+ return ( section_id < _num_bsp_sections ) ?
+ section_strings[ section_id - _num_single_sections ] : NULL;
+ }
+ return sectionname;
+}
+
+
+// BspFormat specific static variables ----------------------------------------
+//
+const char BspFormat::_bspsig_str[] = "#BSP";
+const char BspFormat::BSP_FILE_EXTENSION[] = ".bsp";
+
+const char BspFormat::_bspspec_polygon_str[] = "polygon";
+const char BspFormat::_bspspec_frontlist_str[] = "frontlist";
+const char BspFormat::_bspspec_backlist_str[] = "backlist";
+const char BspFormat::_bspspec_fronttree_str[] = "fronttree";
+const char BspFormat::_bspspec_backtree_str[] = "backtree";
+const char BspFormat::_bspspec_plane_str[] = "plane";
+const char BspFormat::_bspspec_boundingbox_str[] = "boundingbox";
+
+const char BspFormat::_bsptree_str[] = "#bsptree";
+const char BspFormat::_polygons_str[] = "#polygons";
+
+// additional section names table
+const char *BspFormat::section_strings[] = {
+ _bsptree_str,
+ _polygons_str
+};
+const int BspFormat::section_ids[] = {
+ _bsptree,
+ _polygons
+};
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BspFormat.h b/tool_src/BspLib/BspFormat.h
new file mode 100644
index 0000000..9097a80
--- /dev/null
+++ b/tool_src/BspLib/BspFormat.h
@@ -0,0 +1,77 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspFormat.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPFORMAT_H_
+#define _BSPFORMAT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SingleFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class containing bsp format specifics --------------------------------------
+//
+class BspFormat : public virtual SingleFormat {
+
+protected:
+
+ // section enumeration
+ // (additional sections not supported by SingleFormat)
+ enum {
+ _bsptree = _num_single_sections,
+ _polygons,
+
+ _num_bsp_sections
+ };
+
+public:
+ BspFormat() { }
+ ~BspFormat() { }
+
+ BspFormat( const BspFormat& copyobj ) : SingleFormat( copyobj ) { }
+ BspFormat& operator =( const BspFormat& copyobj );
+
+protected:
+ static int GetSectionId( char *section_name );
+ static const char* GetSectionName( int section_id );
+
+public:
+ static const char _bspspec_polygon_str[];
+ static const char _bspspec_frontlist_str[];
+ static const char _bspspec_backlist_str[];
+ static const char _bspspec_fronttree_str[];
+ static const char _bspspec_backtree_str[];
+ static const char _bspspec_plane_str[];
+ static const char _bspspec_boundingbox_str[];
+
+protected:
+ static const char _bspsig_str[];
+ static const char BSP_FILE_EXTENSION[];
+
+ static const char _bsptree_str[];
+ static const char _polygons_str[];
+
+ static const char* section_strings[];
+ static const int section_ids[];
+};
+
+// assignment operator --------------------------------------------------------
+inline BspFormat& BspFormat::operator =( const BspFormat& copyobj )
+{
+ *(SingleFormat *)this = copyobj;
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPFORMAT_H_
+
diff --git a/tool_src/BspLib/BspInput.cpp b/tool_src/BspLib/BspInput.cpp
new file mode 100644
index 0000000..b124e88
--- /dev/null
+++ b/tool_src/BspLib/BspInput.cpp
@@ -0,0 +1,406 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BspInput.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspInput.h"
+#include "BspObject.h"
+#include "BspTool.h"
+#include "BoundingBox.h"
+#include "Plane.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file is read and parsed immediately after construction of an object --------
+//
+BspInput::BspInput( BspObjectList objectlist, const char *filename ) :
+ SingleInput( objectlist, filename )
+{
+ ParseObjectData();
+}
+
+
+// destructor destroys only class members and base classes --------------------
+//
+BspInput::~BspInput()
+{
+}
+
+
+// assignment copies only the BspFormat part of the object --------------------
+//
+BspInput& BspInput::operator =( const BspInput& copyobj )
+{
+ *(BspFormat *)this = copyobj;
+ return *this;
+}
+
+
+// print error message if error in object data-file ---------------------------
+//
+void BspInput::ParseError( int section )
+{
+ //NOTE:
+ // GetSectionName() is overloaded and not virtual, therefore
+ // SingleInput's ParseError() cannot be used!
+ sprintf( line, "%sin section %s (line %d)", parser_err_str,
+ GetSectionName( section ), m_parser_lineno );
+ ErrorMessage( line );
+ HandleCriticalError();
+}
+
+
+// correct mapping coordinates if object scale, translation, etc. applied -----
+//
+void BspInput::CorrectMappingCoordinates()
+{
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ int numfaces = facelist.getNumElements();
+ for ( int i = 0; i < numfaces; i++ )
+ if ( facelist[ i ].MappingAttached() )
+ for ( int j = 0; j < 3; j++ ) {
+ Vertex2 vtx = facelist[ i ].MapXY( j );
+ vtx.setX( vtx.getX() - NewOriginX );
+ vtx.setY( vtx.getY() - NewOriginY );
+ vtx.setW( vtx.getW() - NewOriginZ );
+ if ( PostProcessingFlags & FILTER_SCALE_FACTORS ) {
+ vtx.setX( vtx.getX() * ObjScaleX );
+ vtx.setY( vtx.getY() * ObjScaleY );
+ vtx.setW( vtx.getW() * ObjScaleZ );
+ }
+ facelist[ i ].MapXY( j ) = vtx;
+ }
+}
+
+
+// read polygon index list for current face -----------------------------------
+//
+void BspInput::ReadPolyIndxs( int& facesread )
+{
+ while ( m_scanptr != NULL ) {
+ // only end-of-line or comment terminates index-list
+ if ( *m_scanptr == ';' ) break;
+ // read polygon id
+ int polynumber;
+ ReadIntParameter( polynumber, 1 );
+ // find polygon referenced via its id
+ Polygon *poly = m_baseobject->getPolygonList().FindPolygon( polynumber );
+
+ if ( poly != NULL ) {
+ if ( poly->getFaceId() != -1 )
+ ParseError( m_section );
+ // store faceindex into polygon (converted to 0-start)
+ poly->setFaceId( facesread );
+ } else {
+ sprintf( line, "%s[Polygonindex invalid]: polygon %d in line %d\n",
+ parser_err_str, polynumber + 1, m_parser_lineno );
+ ErrorMessage( line );
+ HandleCriticalError();
+ }
+
+ m_scanptr = strtok( NULL, ",/ \t\n\r" );
+ }
+
+ facesread++;
+}
+
+
+// read face correspondences as direct three point mapping --------------------
+//
+void BspInput::ReadDirectCorrespondences( int& mappingsread )
+{
+ FaceChunk& facelist = m_baseobject->getFaceList();
+
+ int texmapcount = 0;
+ int corrfaceno = 0;
+ for ( corrfaceno = 0; corrfaceno < facelist.getNumElements(); corrfaceno++ ) {
+ if ( facelist[ corrfaceno ].FaceTexMapped() )
+ ++texmapcount;
+ if ( texmapcount > mappingsread )
+ break;
+ }
+
+ if ( corrfaceno == facelist.getNumElements() ) {
+ sprintf( line, "%s[Too many mappings specified]: line %d\n",
+ parser_err_str, m_parser_lineno );
+ ErrorMessage( line );
+ HandleCriticalError();
+ }
+
+ double x, y, z;
+ ReadThreeDoubles( x, y, z );
+ facelist[ corrfaceno ].MapXY( 0 ) = Vertex2( x, y, z );
+
+ for ( int k = 1; k < 6; k++ ) {
+ if ( m_input.ReadLine( line, TEXTLINE_MAX ) == NULL )
+ ParseError( m_section );
+ m_parser_lineno++;
+ if ( ( m_scanptr = strtok( line, ",/ \t\n\r" ) ) == NULL )
+ continue;
+ ReadThreeDoubles( x, y, z );
+ if ( k < 3 ) {
+ facelist[ corrfaceno ].MapXY( k ) = Vertex2( x, y, z );
+ } else {
+ facelist[ corrfaceno ].MapUV( k - 3 ) = Vertex2( x, y, z );
+ }
+ }
+
+ mappingsread++;
+}
+
+
+// read single node into bsp tree ---------------------------------------------
+//
+void BspInput::ReadBspTree()
+{
+ int polynumber = -1;
+ int clistindx = 0;
+ int blistindx = 0;
+ int fstindx = 0;
+ int bstindx = 0;
+
+ Plane *separator = NULL;
+ BoundingBox *box = NULL;
+
+ //NOTE:
+ // m_scanptr points to "<nodenumber>:", but the
+ // nodenumber contained in the file is ignored!
+
+ m_scanptr = strtok( NULL, ", \t\n\r" );
+
+ if ( isdigit( *m_scanptr ) ) {
+
+ // read polygon number
+ ReadIntParameter( polynumber, 1 );
+
+ // read nodenumber of head of contained list
+ m_scanptr = strtok( NULL, "|, \t\n\r" );
+ ReadIntParameter( clistindx, 0 );
+
+ // read nodenumber of head of backlist
+ m_scanptr = strtok( NULL, "|, \t\n\r" );
+ ReadIntParameter( blistindx, 0 );
+
+ //NOTE:
+ // the specification of a front- and back-subtree may be
+ // omitted. empty subtrees (nil) will be assumed.
+
+ // read index of front- and back-subtree if not contained node
+ if ( ( m_scanptr = strtok( NULL, "|-, \t\n\r" ) ) != NULL ) {
+ ReadIntParameter( fstindx, 0 );
+ m_scanptr = strtok( NULL, "|-, \t\n\r" );
+ ReadIntParameter( bstindx, 0 );
+ }
+
+ } else do {
+
+ // read line specified in new format (key/value style)
+ char *property = m_scanptr;
+ int error = 1;
+ if ( ( m_scanptr = strtok( NULL, " \t\n\r" ) ) != NULL ) {
+ if ( stricmp( property, _bspspec_polygon_str ) == 0 ) {
+ ReadIntParameter( polynumber, 1 );
+ error = 0;
+ } else if ( stricmp( property, _bspspec_frontlist_str ) == 0 ) {
+ ReadIntParameter( clistindx, 0 );
+ error = 0;
+ } else if ( stricmp( property, _bspspec_backlist_str ) == 0 ) {
+ ReadIntParameter( blistindx, 0 );
+ error = 0;
+ } else if ( stricmp( property, _bspspec_fronttree_str ) == 0 ) {
+ ReadIntParameter( fstindx, 0 );
+ error = 0;
+ } else if ( stricmp( property, _bspspec_backtree_str ) == 0 ) {
+ ReadIntParameter( bstindx, 0 );
+ error = 0;
+ } else if ( stricmp( property, _bspspec_plane_str ) == 0 ) {
+ double x, y, z, d;
+ ReadFourDoubles( x, y, z, d );
+ Vertex3 normal( x, y, z );
+ separator = new Plane( normal, d );
+ error = 0;
+ } else if ( stricmp( property, _bspspec_boundingbox_str ) == 0 ) {
+ Vertex3 v1, v2;
+ ReadSixDoubles( v1, v2 );
+ box = new BoundingBox( v1, v2 );
+ error = 0;
+ }
+ }
+ if ( error ) {
+ {
+ StrScratch error;
+ sprintf( error, "%s[Invalid property of bspnode]: %s (line %d)",
+ parser_err_str, property, m_parser_lineno );
+ ErrorMessage( error );
+ }
+ HandleCriticalError();
+ }
+
+ } while ( ( m_scanptr = strtok( NULL, " \t\n\r" ) ) != NULL );
+
+ // find polygon referenced via its id
+ Polygon *poly = NULL;
+ if ( polynumber >= 0 ) {
+ poly = m_baseobject->getPolygonList().FindPolygon( polynumber );
+ if ( poly == NULL ) {
+ sprintf( line, "%s[Polygonindex in bsp tree invalid]: %d\n",
+ parser_err_str, polynumber + 1 );
+ ErrorMessage( line );
+ HandleCriticalError();
+ }
+ }
+
+ // append new node to flat bsp tree
+ BSPTreeFlat& flatbsp = m_baseobject->getBSPTreeFlat();
+ BSPNodeFlat *flatnode = flatbsp.AppendNode( fstindx, bstindx, poly, clistindx, blistindx );
+
+ if ( separator != NULL ) {
+ // attach separator plane
+ flatnode->setSeparatorPlane( separator );
+ }
+ if ( box != NULL ) {
+ // attach bounding box
+ flatnode->setBoundingBox( box );
+ }
+}
+
+
+// parse object data-file -----------------------------------------------------
+//
+int BspInput::ParseObjectData()
+{
+ int facedef_itemsread = 0;
+ int faceprop_itemsread = 0;
+ int facenorm_itemsread = 0;
+ int mappdef_itemsread = 0;
+
+ InfoMessage( "Processing input data file (format='BSP V1.1') ..." );
+
+ // parse sections and read data -------------------------------
+ m_section = _nil;
+ while ( m_input.ReadLine( line, TEXTLINE_MAX ) != NULL ) {
+
+ if ( ( m_parser_lineno++ & PARSER_DOT_SIZE ) == 0 )
+ printf( "." ), fflush( stdout );
+
+ if ( ( m_scanptr = strtok( line, "/, \t\n\r" ) ) == NULL )
+ continue;
+ else if ( *m_scanptr == ';' )
+ continue;
+ else if ( strnicmp( m_scanptr, "<end", 4 ) == 0 )
+ break;
+ else if ( *m_scanptr == '#' ) {
+ if ( strncmp( m_scanptr, _bspsig_str, strlen( _bspsig_str ) ) == 0 ) {
+ m_section = _comment;
+ } else if ( ( m_section = GetSectionId( m_scanptr ) ) == _nil ) {
+ {
+ StrScratch error;
+ sprintf( error, "%s[Undefined section-name]: %s (line %d)",
+ parser_err_str, m_scanptr, m_parser_lineno );
+ ErrorMessage( error );
+ }
+ HandleCriticalError();
+ }
+ } else {
+ switch ( m_section ) {
+
+ // list of vertices ------------------------------------
+ case _vertices :
+ ReadVertex();
+ break;
+
+ // vertexnums of polygons ------------------------------
+ case _polygons :
+ ReadFace( FALSE );
+ break;
+
+ // definition of faces (consisting of polygons) --------
+ case _faces :
+ ReadPolyIndxs( facedef_itemsread );
+ break;
+
+ // bsptree ---------------------------------------------
+ case _bsptree :
+ ReadBspTree();
+ break;
+
+ // normals for face's planes ---------------------------
+ case _facenormals :
+ ReadFaceNormal( facenorm_itemsread );
+ break;
+
+ // properties of faces ---------------------------------
+ case _faceproperties :
+ ReadFaceProperties( faceprop_itemsread );
+ break;
+
+ // texture->face correspondences ----------------------
+ case _correspondences :
+ ReadDirectCorrespondences( mappdef_itemsread );
+ break;
+
+ // texturing data -----------------------------------
+ case _textures :
+ ReadTextures();
+ break;
+
+ // location of the object ---------------------------
+ case _worldlocation :
+ ReadWorldLocation();
+ break;
+
+ // location of camera -------------------------------
+ case _camera :
+ ReadCameraLocation();
+ break;
+
+ // filename of palette file -------------------------
+ case _palette :
+ ReadPaletteFilename();
+ break;
+
+ // scalefactors for object --------------------------
+ case _scalefactors :
+ ReadScaleFactors();
+ break;
+
+ // exchange command for axes ------------------------
+ case _xchange :
+ ReadXChangeCommand();
+ break;
+
+ // set new object origin ----------------------------
+ case _setorigin :
+ ReadOrigin();
+ break;
+
+ }
+ }
+ }
+
+ // do post processing after parse
+ CorrectMappingCoordinates();
+ ApplyOriginTranslation();
+ FilterAxesDirSwitch();
+ FilterScaleFactors();
+ FilterAxesExchange();
+ EnforceMaximumExtents();
+ m_baseobject->CheckParsedData();
+
+ InfoMessage( "\nObject data ok.\n" );
+
+ // do colorindex to rgb conversion
+ ConvertColIndxs();
+
+ return ( m_inputok = TRUE );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BspInput.h b/tool_src/BspLib/BspInput.h
new file mode 100644
index 0000000..930e112
--- /dev/null
+++ b/tool_src/BspLib/BspInput.h
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspInput.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPINPUT_H_
+#define _BSPINPUT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspFormat.h"
+#include "SingleInput.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file input class for bsp format files --------------------------------------
+//
+class BspInput : public BspFormat, public SingleInput {
+
+public:
+ BspInput( BspObjectList objectlist, const char *filename );
+ ~BspInput();
+
+ BspInput& operator =( const BspInput& copyobj );
+
+public:
+ int ParseObjectData();
+
+private:
+ void CorrectMappingCoordinates();
+ void ReadPolyIndxs( int& facesread );
+ void ReadDirectCorrespondences( int& facesread );
+ void ReadBspTree();
+
+protected:
+ void ParseError( int section );
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPINPUT_H_
+
diff --git a/tool_src/BspLib/BspLib.vcproj b/tool_src/BspLib/BspLib.vcproj
new file mode 100755
index 0000000..93507ab
--- /dev/null
+++ b/tool_src/BspLib/BspLib.vcproj
@@ -0,0 +1,1055 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="BspLib"
+ SccProjectName="&quot;$/ParsecTools/BspLib&quot;, KUFAAAAA"
+ SccLocalPath=".">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\BspLib;..\QvLib"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;VIEW_BSP"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/BspLib.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Debug\BspLib.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="3079"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\BspLib;..\QvLib"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;VIEW_BSP"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/BspLib.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Release\BspLib.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="3079"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="AodFormat.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="AodInput.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="AodOutput.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BoundingBox.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BRep.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BspFormat.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BspInput.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BSPNode.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BspObject.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BspObjectList.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BspOutput.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BspTool.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="BSPTree.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="EpsAreas.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Face.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="InputData3D.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="IOData3D.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="LineSeg.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Mapping.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="ObjectAodFormat.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="ObjectBinFormat.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="ObjectBspFormat.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="ObjectBSPNode.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="OutputData3D.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Polygon.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="PolygonList.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="SingleFormat.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="SingleInput.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="SingleOutput.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="SystemIO.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Texture.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Transform2.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Transform3.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="TriMapping.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Vertex.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="VertexChunk.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="VrmlFile.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="AodFormat.h">
+ </File>
+ <File
+ RelativePath="AodInput.h">
+ </File>
+ <File
+ RelativePath="AodOutput.h">
+ </File>
+ <File
+ RelativePath="BoundingBox.h">
+ </File>
+ <File
+ RelativePath="BRep.h">
+ </File>
+ <File
+ RelativePath="BspFormat.h">
+ </File>
+ <File
+ RelativePath="BspInput.h">
+ </File>
+ <File
+ RelativePath="BspLibDefs.h">
+ </File>
+ <File
+ RelativePath="BSPNode.h">
+ </File>
+ <File
+ RelativePath="BspObject.h">
+ </File>
+ <File
+ RelativePath="BspObjectList.h">
+ </File>
+ <File
+ RelativePath="BspOutput.h">
+ </File>
+ <File
+ RelativePath="BspTool.h">
+ </File>
+ <File
+ RelativePath="BSPTree.h">
+ </File>
+ <File
+ RelativePath="Chunk.h">
+ </File>
+ <File
+ RelativePath="Debug.h">
+ </File>
+ <File
+ RelativePath="Face.h">
+ </File>
+ <File
+ RelativePath="InputData3D.h">
+ </File>
+ <File
+ RelativePath="IOData3D.h">
+ </File>
+ <File
+ RelativePath="LineSeg2.h">
+ </File>
+ <File
+ RelativePath="LineSeg3.h">
+ </File>
+ <File
+ RelativePath="Mapping.h">
+ </File>
+ <File
+ RelativePath="Material.h">
+ </File>
+ <File
+ RelativePath="ObjectAodFormat.h">
+ </File>
+ <File
+ RelativePath="ObjectBinFormat.h">
+ </File>
+ <File
+ RelativePath="ObjectBspFormat.h">
+ </File>
+ <File
+ RelativePath="ObjectBSPNode.h">
+ </File>
+ <File
+ RelativePath="ObjectBSPTree.h">
+ </File>
+ <File
+ RelativePath="OutputData3D.h">
+ </File>
+ <File
+ RelativePath="Plane.h">
+ </File>
+ <File
+ RelativePath="Polygon.h">
+ </File>
+ <File
+ RelativePath="PolygonList.h">
+ </File>
+ <File
+ RelativePath="SingleFormat.h">
+ </File>
+ <File
+ RelativePath="SingleInput.h">
+ </File>
+ <File
+ RelativePath="SingleOutput.h">
+ </File>
+ <File
+ RelativePath="SystemIO.h">
+ </File>
+ <File
+ RelativePath="Texture.h">
+ </File>
+ <File
+ RelativePath="Transform2.h">
+ </File>
+ <File
+ RelativePath="Transform3.h">
+ </File>
+ <File
+ RelativePath="TriMapping.h">
+ </File>
+ <File
+ RelativePath="Vector.h">
+ </File>
+ <File
+ RelativePath="Vector2.h">
+ </File>
+ <File
+ RelativePath="Vector3.h">
+ </File>
+ <File
+ RelativePath="Vertex.h">
+ </File>
+ <File
+ RelativePath="Vertex2.h">
+ </File>
+ <File
+ RelativePath="Vertex3.h">
+ </File>
+ <File
+ RelativePath="VertexChunk.h">
+ </File>
+ <File
+ RelativePath="VrmlFile.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tool_src/BspLib/BspLib.vcxproj b/tool_src/BspLib/BspLib.vcxproj
new file mode 100755
index 0000000..f1133db
--- /dev/null
+++ b/tool_src/BspLib/BspLib.vcxproj
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <SccProjectName>"$/ParsecTools/BspLib", KUFAAAAA</SccProjectName>
+ <SccLocalPath>.</SccLocalPath>
+ <ProjectGuid>{AA6FAB40-A936-486C-9DB0-1ADDFFCD4D00}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v110</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v110</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>.\Debug\</OutDir>
+ <IntDir>.\Debug\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>.\Release\</OutDir>
+ <IntDir>.\Release\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\BspLib;..\QvLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;VIEW_BSP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader />
+ <PrecompiledHeaderOutputFile>.\Debug/BspLib.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <BrowseInformation>true</BrowseInformation>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>.\Debug\BspLib.lib</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0c07</Culture>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>..\BspLib;..\QvLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;VIEW_BSP;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader />
+ <PrecompiledHeaderOutputFile>.\Release/BspLib.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ <Lib>
+ <OutputFile>.\Release\BspLib.lib</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Lib>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0c07</Culture>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="AodFormat.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="AodInput.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="AodOutput.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BoundingBox.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BRep.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BspFormat.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BspInput.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BSPNode.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BspObject.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BspObjectList.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BspOutput.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BspTool.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="BSPTree.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="EpsAreas.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Face.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="InputData3D.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="IOData3D.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="LineSeg.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Mapping.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="ObjectAodFormat.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="ObjectBinFormat.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="ObjectBspFormat.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="ObjectBSPNode.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="OutputData3D.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Polygon.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="PolygonList.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="SingleFormat.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="SingleInput.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="SingleOutput.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="SystemIO.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Texture.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Transform2.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Transform3.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="TriMapping.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="Vertex.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="VertexChunk.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ <ClCompile Include="VrmlFile.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AodFormat.h" />
+ <ClInclude Include="AodInput.h" />
+ <ClInclude Include="AodOutput.h" />
+ <ClInclude Include="BoundingBox.h" />
+ <ClInclude Include="BRep.h" />
+ <ClInclude Include="BspFormat.h" />
+ <ClInclude Include="BspInput.h" />
+ <ClInclude Include="BspLibDefs.h" />
+ <ClInclude Include="BSPNode.h" />
+ <ClInclude Include="BspObject.h" />
+ <ClInclude Include="BspObjectList.h" />
+ <ClInclude Include="BspOutput.h" />
+ <ClInclude Include="BspTool.h" />
+ <ClInclude Include="BSPTree.h" />
+ <ClInclude Include="Chunk.h" />
+ <ClInclude Include="Debug.h" />
+ <ClInclude Include="Face.h" />
+ <ClInclude Include="InputData3D.h" />
+ <ClInclude Include="IOData3D.h" />
+ <ClInclude Include="LineSeg2.h" />
+ <ClInclude Include="LineSeg3.h" />
+ <ClInclude Include="Mapping.h" />
+ <ClInclude Include="Material.h" />
+ <ClInclude Include="ObjectAodFormat.h" />
+ <ClInclude Include="ObjectBinFormat.h" />
+ <ClInclude Include="ObjectBspFormat.h" />
+ <ClInclude Include="ObjectBSPNode.h" />
+ <ClInclude Include="ObjectBSPTree.h" />
+ <ClInclude Include="OutputData3D.h" />
+ <ClInclude Include="Plane.h" />
+ <ClInclude Include="Polygon.h" />
+ <ClInclude Include="PolygonList.h" />
+ <ClInclude Include="SingleFormat.h" />
+ <ClInclude Include="SingleInput.h" />
+ <ClInclude Include="SingleOutput.h" />
+ <ClInclude Include="SystemIO.h" />
+ <ClInclude Include="Texture.h" />
+ <ClInclude Include="Transform2.h" />
+ <ClInclude Include="Transform3.h" />
+ <ClInclude Include="TriMapping.h" />
+ <ClInclude Include="Vector.h" />
+ <ClInclude Include="Vector2.h" />
+ <ClInclude Include="Vector3.h" />
+ <ClInclude Include="Vertex.h" />
+ <ClInclude Include="Vertex2.h" />
+ <ClInclude Include="Vertex3.h" />
+ <ClInclude Include="VertexChunk.h" />
+ <ClInclude Include="VrmlFile.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/tool_src/BspLib/BspLib.vcxproj.filters b/tool_src/BspLib/BspLib.vcxproj.filters
new file mode 100755
index 0000000..6ba47a2
--- /dev/null
+++ b/tool_src/BspLib/BspLib.vcxproj.filters
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{b92e77c0-0c19-4232-b527-b92d163e8f85}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{3965bcee-c821-4b2c-a5df-99b4f75d7faf}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="AodFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AodInput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AodOutput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BoundingBox.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BRep.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BspFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BspInput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BSPNode.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BspObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BspObjectList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BspOutput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BspTool.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BSPTree.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="EpsAreas.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Face.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InputData3D.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IOData3D.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="LineSeg.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Mapping.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ObjectAodFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ObjectBinFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ObjectBspFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ObjectBSPNode.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="OutputData3D.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Polygon.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PolygonList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SingleFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SingleInput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SingleOutput.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SystemIO.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Texture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Transform2.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Transform3.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="TriMapping.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Vertex.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VertexChunk.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VrmlFile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AodFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="AodInput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="AodOutput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BoundingBox.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BRep.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspInput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspLibDefs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BSPNode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspObjectList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspOutput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BspTool.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BSPTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Chunk.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Face.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InputData3D.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IOData3D.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="LineSeg2.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="LineSeg3.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mapping.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Material.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ObjectAodFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ObjectBinFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ObjectBspFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ObjectBSPNode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ObjectBSPTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="OutputData3D.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Plane.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Polygon.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PolygonList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SingleFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SingleInput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SingleOutput.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SystemIO.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Texture.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Transform2.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Transform3.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="TriMapping.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Vector.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Vector2.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Vector3.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Vertex.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Vertex2.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Vertex3.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VertexChunk.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VrmlFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/tool_src/BspLib/BspLib.vcxproj.user b/tool_src/BspLib/BspLib.vcxproj.user
new file mode 100755
index 0000000..a375ae3
--- /dev/null
+++ b/tool_src/BspLib/BspLib.vcxproj.user
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup />
+</Project> \ No newline at end of file
diff --git a/tool_src/BspLib/BspLibDefs.h b/tool_src/BspLib/BspLibDefs.h
new file mode 100644
index 0000000..c6daca8
--- /dev/null
+++ b/tool_src/BspLib/BspLibDefs.h
@@ -0,0 +1,163 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspLibDefs.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPLIBDEFS_H_
+#define _BSPLIBDEFS_H_
+
+
+// standard C library headers -------------------------------------------------
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
+
+
+// various build dependent macros ---------------------------------------------
+#ifdef _DEBUG
+
+#define PUBLIC
+#define PRIVATE static
+#define D(x) x
+#define CHECK_DEREFERENCING(x) x
+
+#else
+
+#define PUBLIC
+#define PRIVATE static
+#define D(x)
+#define CHECK_DEREFERENCING(x) x
+
+#endif
+
+
+// define NAMESPACE usage -----------------------------------------------------
+#define USE_BSPLIB_NAMESPACE
+
+#ifdef USE_BSPLIB_NAMESPACE
+
+#define BSPLIB_NAMESPACE BspLib
+#define BSPLIB_NAMESPACE_BEGIN namespace BSPLIB_NAMESPACE {
+#define BSPLIB_NAMESPACE_END }
+
+#else
+
+#define BSPLIB_NAMESPACE
+#define BSPLIB_NAMESPACE_BEGIN
+#define BSPLIB_NAMESPACE_END
+
+#endif
+
+
+#ifndef _WIN32
+ #define stricmp strcasecmp
+ #define strnicmp strncasecmp
+#endif
+
+
+// MS VC++ specific macros ----------------------------------------------------
+#ifdef _MSC_VER
+#define PATH_MAX _MAX_PATH
+#endif
+#define _CRT_SECURE_NO_WARNINGS 1
+
+
+// boolean values -------------------------------------------------------------
+#define TRUE 1
+#define FALSE 0
+
+// asm types ------------------------------------------------------------------
+typedef uint8_t byte;
+typedef uint16_t word;
+typedef uint32_t dword;
+
+// data types for coordinates -------------------------------------------------
+typedef int32_t fixed_t;
+typedef double hprec_t;
+
+// conversion macros for 3 and 2 digit values ---------------------------------
+#define DIG3_TO_STR( s, a ) (s)[0]=(((a)/100)%10)+'0';\
+ (s)[1]=(((a)/10)%10)+'0'; \
+ (s)[2]=((a)%10)+'0'; \
+ (s)[3]='\0';
+
+#define DIG2_TO_STR( s, a ) (s)[0]=(((a)/10)%10)+'0'; \
+ (s)[1]=((a)%10)+'0'; \
+ (s)[2]='\0';
+
+
+// some general structures ----------------------------------------------------
+//
+BSPLIB_NAMESPACE_BEGIN
+
+
+// RGB color triplet using bytes as members -----------------------------------
+struct ColorRGB {
+ byte R;
+ byte G;
+ byte B;
+};
+
+// RGB color triplet plus alpha using bytes as members ------------------------
+struct ColorRGBA {
+ byte R;
+ byte G;
+ byte B;
+ byte A;
+};
+
+// RGB color triplet using floats as members ----------------------------------
+struct ColorRGBf {
+ float R;
+ float G;
+ float B;
+};
+
+// RGB color triplet plus alpha using floats as members -----------------------
+struct ColorRGBAf {
+ float R;
+ float G;
+ float B;
+ float A;
+};
+
+
+// epsilon area specifications ------------------------------------------------
+//
+#define EPS_SCALAR EpsAreas::eps_scalarproduct
+#define EPS_COMP_ZERO EpsAreas::eps_vanishcomponent
+#define EPS_DENOM_ZERO EpsAreas::eps_vanishdenominator
+#define EPS_POINT_ON_PLANE EpsAreas::eps_planethickness
+#define EPS_POINT_ON_LINE EpsAreas::eps_pointonline
+#define EPS_POINT_ON_LINESEG EpsAreas::eps_pointonlineseg
+#define EPS_VERTEX_MERGE EpsAreas::eps_vertexmergearea
+
+class EpsAreas {
+
+public:
+ static double eps_scalarproduct; // epsilon area for general scalar product comparisons
+ static double eps_vanishcomponent; // epsilon area for vanishing vector components
+ static double eps_vanishdenominator; // epsilon area for vanishing denominators
+ static double eps_planethickness; // epsilon area for width of "infinitely thin" plane
+ static double eps_pointonline; // epsilon area for point on line determination
+ static double eps_pointonlineseg; // epsilon area for point on lineseg parameter (t)
+ static double eps_vertexmergearea; // epsilon area for merging of vertices
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPLIBDEFS_H_
+
+
+
+
diff --git a/tool_src/BspLib/BspObject.cpp b/tool_src/BspLib/BspObject.cpp
new file mode 100644
index 0000000..688c2c0
--- /dev/null
+++ b/tool_src/BspLib/BspObject.cpp
@@ -0,0 +1,641 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BspObject.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspObject.h"
+#include "BoundingBox.h"
+#include "IOData3D.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+// flags
+#define NO_CONSISTENCY_CHECKS
+
+
+// constructor for BspObjectInfo ----------------------------------------------
+//
+BspObjectInfo::BspObjectInfo()
+{
+ numvertices = 0;
+ numpolygons = 0;
+ numfaces = 0;
+ numtextures = 0;
+ numcorrespondences = 0;
+
+ numnormals = 0;
+ numtexmappedfaces = 0;
+
+ numvertices_in = 0;
+ numpolygons_in = 0;
+ numfaces_in = 0;
+
+ numbsppolygons = 0;
+ numpolygons_before_bsp = 0;
+
+ numtracevertices = 0;
+ nummultvertices = 0;
+ numsplitquadrilaterals = 0;
+}
+
+
+// constructor for BspObject --------------------------------------------------
+//
+BspObject::BspObject() : polygonlist( this )
+{
+ objectname = NULL; // no object name attached
+ next = NULL; // empty list
+ objecttrafo.LoadIdentity(); // load identity transformation
+}
+
+
+// set object's name (string is copied into the object!) ----------------------
+//
+void BspObject::setObjectName( char *name )
+{
+ delete objectname;
+ if ( name != NULL ) {
+ objectname = new char[ strlen( name ) + 1 ];
+ strcpy( objectname, name );
+ } else {
+ objectname = NULL;
+ }
+}
+
+
+// convert all faces with colorindexes to rgb triplets ------------------------
+//
+int BspObject::ConvertColorIndexesToRGB( char *palette, int changemode )
+{
+ int did_convert = FALSE;
+ for ( int i = 0; i < facelist.getNumElements(); i++ )
+ if ( facelist[ i ].ConvertColorIndexToRGB( palette, changemode ) )
+ did_convert = TRUE;
+ return did_convert;
+}
+
+
+// print inconsistency error message ------------------------------------------
+//
+void BspObject::InconsistencyError( const char *err )
+{
+ if ( err != NULL ) {
+ StrScratch message;
+ sprintf( message, "**ERROR** [Inconsistencies]: %s", err );
+ ErrorMessage( message );
+ }
+ HandleCriticalError();
+}
+
+
+// update entity counts of contained attribute lists --------------------------
+//
+void BspObject::UpdateAttributeNumbers()
+{
+ numvertices = vertexlist.getNumElements();
+ numpolygons = polygonlist.getNumElements();
+ numfaces = facelist.getNumElements();
+ numtextures = texturelist.getNumElements();
+ numcorrespondences = mappinglist.getNumElements();
+
+ numnormals = 0;
+ numtexmappedfaces = 0;
+
+ for ( int i = 0; i < numfaces; i++ ) {
+ // count number of faces with already calculated normals
+ if ( facelist[ i ].NormalValid() )
+ numnormals++;
+ // count number of texture mapped faces
+ if ( facelist[ i ].FaceTexMapped() )
+ numtexmappedfaces++;
+ }
+}
+
+
+// process data immediately after parse was done ------------------------------
+//
+void BspObject::CheckParsedData()
+{
+ // calculate entity counts
+ UpdateAttributeNumbers();
+
+ // remember number of input entities
+ numvertices_in = numvertices;
+ numpolygons_in = numpolygons;
+ numfaces_in = numfaces;
+
+#if !defined( NO_CONSISTENCY_CHECKS ) && !defined( VIEW_BSP )
+
+ // consistency checks
+ if ( numpolygons != numfaces )
+ InconsistencyError( "properties must be defined for every face!" );
+ if ( numcorrespondences != numtexmappedfaces )
+ InconsistencyError( "mapping must be specified for every texturemapped face!" );
+#endif
+
+}
+
+
+// display statistics (number of vertices, faces, polygons, etc.) -------------
+//
+void BspObject::DisplayStatistics()
+{
+ UpdateAttributeNumbers();
+
+ StrScratch message;
+ sprintf( message, "\n--- Statistics ---------------------\n" );
+
+#define sprintf InfoMessage( message ); sprintf
+
+ sprintf( message, "\nINPUT\n" );
+ sprintf( message, " Vertices = %d\n", numvertices_in );
+ sprintf( message, " Faces = %d\n", numfaces_in );
+ sprintf( message, " Polygons = %d\n", numpolygons_in );
+
+ sprintf( message, "\nOUTPUT\n" );
+ sprintf( message, " Vertices = %d\n", numvertices );
+ sprintf( message, " Faces = %d\n", numfaces );
+ sprintf( message, " Polygons = %d\n", numbsppolygons );
+
+ sprintf( message, "\nGENERAL\n" );
+ sprintf( message, " Textures = %d\n", numtextures );
+ sprintf( message, " TexFaces = %d\n", numtexmappedfaces );
+
+ sprintf( message, "\nANALYSIS\n" );
+ sprintf( message, " Inserted vertices = %d\n", numvertices - numvertices_in );
+ sprintf( message, " Inserted polygons = %d (%d split by bsp; %d split as quadrilateral)\n",
+ numbsppolygons - numpolygons_in,
+ numbsppolygons - numpolygons_in - numsplitquadrilaterals,
+ numsplitquadrilaterals );
+ sprintf( message, " Tracevertices = %d\n", numtracevertices );
+ sprintf( message, " Multiple vertices = %d\n", nummultvertices );
+
+ sprintf( message, "\n------------------------------------\n\n" );
+ InfoMessage( message );
+
+#undef sprintf
+
+}
+
+
+// scale entire object (correct vertices and mappings) ------------------------
+//
+void BspObject::ApplyScale( double scalefac )
+{
+ // scale entire vertex list
+ numvertices = vertexlist.getNumElements();
+ int i = 0;
+ for ( i = 0; i < numvertices; i++ ) {
+ vertexlist[ i ].setX( vertexlist[ i ].getX() * scalefac );
+ vertexlist[ i ].setY( vertexlist[ i ].getY() * scalefac );
+ vertexlist[ i ].setZ( vertexlist[ i ].getZ() * scalefac );
+ }
+ // scale (x,y,z) part of mappings
+ numfaces = facelist.getNumElements();
+ for ( i = 0; i < numfaces; i++ ) {
+ if ( facelist[ i ].MappingAttached() ) {
+ for ( int j = 0; j < 3; j++ ) {
+ Vertex2 vtx = facelist[ i ].MapXY( j );
+ vtx.setX( vtx.getX() * scalefac );
+ vtx.setY( vtx.getY() * scalefac );
+ vtx.setW( vtx.getW() * scalefac );
+ facelist[ i ].MapXY( j ) = vtx;
+ }
+ }
+ }
+}
+
+
+// apply translation to all coordinates and set center to (0,0,0) -------------
+//
+void BspObject::ApplyCenter()
+{
+ // get center
+ Vector3 cvec = objecttrafo.ExtractTranslation();
+ double cx = cvec.getX();
+ double cy = cvec.getY();
+ double cz = cvec.getZ();
+
+ // translate all vertices
+ numvertices = vertexlist.getNumElements();
+ for ( int i = 0; i < numvertices; i++ ) {
+ vertexlist[ i ].setX( vertexlist[ i ].getX() + cx );
+ vertexlist[ i ].setY( vertexlist[ i ].getY() + cy );
+ vertexlist[ i ].setZ( vertexlist[ i ].getZ() + cz );
+ }
+}
+
+
+// apply transformation matrix and set to identity afterwards -----------------
+//
+void BspObject::ApplyTransformation()
+{
+ // transform all vertices
+ numvertices = vertexlist.getNumElements();
+ for ( int i = 0; i < numvertices; i++ ) {
+ vertexlist[ i ] = objecttrafo.TransformVector3( vertexlist[ i ] );
+ }
+
+ objecttrafo.LoadIdentity();
+}
+
+
+// calculate axial bounding box -----------------------------------------------
+//
+void BspObject::CalcBoundingBox( Vertex3& minvertex, Vertex3& maxvertex )
+{
+ //NOTE:
+ // if a transformation is attached, only the translation is
+ // taken into account. so, the bounding box is not correct if,
+ // for instance, a rotation is attached.
+ // thus, ApplyTransformation() is normally invoked before
+ // bounding boxes are calculated.
+
+ // fetch object's location in world space
+ Vector3 worldcenter = objecttrafo.FetchTranslation();
+
+ if ( ( numvertices = vertexlist.getNumElements() ) < 1 ) {
+ minvertex = worldcenter;
+ maxvertex = worldcenter;
+ return;
+ }
+
+ // start with first vertex
+ minvertex = vertexlist[ 0 ];
+ maxvertex = vertexlist[ 0 ];
+
+ // test all other vertices
+ for ( int i = 1; i < numvertices; i++ ) {
+ Vertex3& testvertex = vertexlist[ i ];
+
+ if ( testvertex.getX() < minvertex.getX() )
+ minvertex.setX( testvertex.getX() );
+ if ( testvertex.getY() < minvertex.getY() )
+ minvertex.setY( testvertex.getY() );
+ if ( testvertex.getZ() < minvertex.getZ() )
+ minvertex.setZ( testvertex.getZ() );
+
+ if ( testvertex.getX() > maxvertex.getX() )
+ maxvertex.setX( testvertex.getX() );
+ if ( testvertex.getY() > maxvertex.getY() )
+ maxvertex.setY( testvertex.getY() );
+ if ( testvertex.getZ() > maxvertex.getZ() )
+ maxvertex.setZ( testvertex.getZ() );
+ }
+
+ minvertex += worldcenter;
+ maxvertex += worldcenter;
+}
+
+
+// check planes of all polygons contained in polygonlist ----------------------
+//
+void BspObject::CheckPolygonPlanes()
+{
+ // scan linear polygon list and check planes of all polygons
+ polygonlist.CheckPolygonPlanes();
+
+ // counts have to be updated; CheckPolygonPlanes() may have
+ // created new vertices, polygons, and faces
+ UpdateAttributeNumbers();
+
+ if( numnormals != numfaces ) {
+ ErrorMessage( "***ERROR*** Inconsistencies in normals!" );
+ HandleCriticalError();
+ }
+
+ if ( numsplitquadrilaterals > 0 ) {
+ StrScratch message;
+ sprintf( message, "\n%d quadrilaterals were split into triangles.\n",
+ numsplitquadrilaterals );
+ InfoMessage( message );
+ }
+}
+
+
+// check for multiple vertices in vertexlist ----------------------------------
+//
+void BspObject::CheckVertices( int verbose )
+{
+ // determine number of equal vertices in vertexlist
+ nummultvertices = vertexlist.CheckVertices( verbose );
+}
+
+
+// calculate bounding boxes for all nodes of bsp tree -------------------------
+//
+void BspObject::CalcBoundingBoxes()
+{
+ if ( !bsptree.TreeEmpty() ) {
+ InfoMessage( "\nCalculating bounding boxes for bsp-tree nodes...\n" );
+ bsptree->CalcBoundingBoxes();
+ }
+}
+
+
+// calculate separator planes for all polygon-nodes of bsp tree ---------------
+//
+void BspObject::CalcSeparatorPlanes()
+{
+ if ( !bsptree.TreeEmpty() ) {
+ InfoMessage( "\nCalculating explicit separator planes for bsp-tree nodes...\n" );
+ bsptree->CalcSeparatorPlanes();
+ }
+}
+
+
+// check edges of polygons contained in bsp tree for t-vertices ---------------
+//
+void BspObject::CheckEdges()
+{
+ if ( !bsptree.TreeEmpty() ) {
+ InfoMessage( "\nChecking edges of bsp-tree polygons...\n" );
+ bsptree->CheckEdges();
+ }
+}
+
+
+// calculate plane normals for all polygons -----------------------------------
+//
+void BspObject::CalcPlaneNormals()
+{
+ // scan linear polygon list and calculate normals for all polygons
+ polygonlist.CalcPlaneNormals();
+}
+
+
+// build a list of bounding boxes containing all objects of list --------------
+//
+BoundingBox *BspObject::BuildBoundingBoxList()
+{
+ // build bounding box list as secondary data structure.
+ // there is a bounding box for every object; order is reversed!
+ BoundingBox *headbox = NULL;
+ for ( BspObject *obj = this; obj; obj = obj->getNext() ) {
+ headbox = new BoundingBox( obj, headbox );
+ }
+
+ return headbox;
+}
+
+
+// build bsp tree and store pointer into object structure ---------------------
+//
+BSPNode *BspObject::BuildBSPTree()
+{
+ if ( bsptree.TreeEmpty() ) {
+ InfoMessage( "\nCompiling bsp tree...\n" );
+ numpolygons_before_bsp = numpolygons;
+ bsptree.InitTree( polygonlist.PartitionSpace() );
+ }
+
+ return bsptree.getRoot();
+}
+
+
+// build linked bsp tree from flat bsp tree -----------------------------------
+//
+BSPNode *BspObject::BuildBSPTreeFromFlat()
+{
+ if ( bsptree.TreeEmpty() ) {
+ InfoMessage( "\nBuilding linked bsp-tree from flat representation...\n" );
+ bsptree.InitTree( bsptreeflat.BuildBSPTree( 1 ) );
+ // linear list of polygons is not valid anymore!
+ polygonlist.InvalidateList();
+ }
+
+ return bsptree.getRoot();
+}
+
+
+// determine if linked bsp tree is available (non-empty) ----------------------
+//
+int BspObject::BSPTreeAvailable()
+{
+ return !bsptree.TreeEmpty();
+}
+
+
+// determine if flat bsp tree is available (non-empty) ------------------------
+//
+int BspObject::BSPTreeFlatAvailable()
+{
+ return !bsptreeflat.TreeEmpty();
+}
+
+
+// determine if any bsp tree is available (non-empty) -------------------------
+//
+int BspObject::BspTreeAvailable()
+{
+ return ( BSPTreeAvailable() || BSPTreeFlatAvailable() );
+}
+
+
+// merge another BspObject into this object (corrects everything necessary) ---
+//
+void BspObject::MergeObjects( BspObject *mergeobj )
+{
+ if ( mergeobj != NULL ) {
+
+ if ( !check_vertex_doublets_on_merge ) {
+
+ // merge vertex lists
+ int numsourcevertices = vertexlist.getNumElements();
+ int nummergevertices = mergeobj->vertexlist.getNumElements();
+ int i = 0;
+ for ( i = 0; i < nummergevertices; i++ ) {
+ vertexlist.AddVertex( mergeobj->vertexlist[ i ] );
+ }
+ numvertices += nummergevertices;
+ numvertices_in += mergeobj->numvertices_in;
+
+ // merge face lists
+ int numsourcefaces = facelist.getNumElements();
+ int nummergefaces = mergeobj->facelist.getNumElements();
+ for ( i = 0; i < nummergefaces; i++ ) {
+ Face& mergeface = mergeobj->facelist[ i ];
+ mergeface.setId( mergeface.getId() + numsourcefaces );
+ facelist.AddElement( mergeface );
+ }
+ numfaces += nummergefaces;
+ numfaces_in += mergeobj->numfaces_in;
+
+ // correct all polygons
+ if ( !mergeobj->BSPTreeAvailable() ) {
+ // correct entire polygon list
+ Polygon *polylist = mergeobj->polygonlist.FetchHead();
+ for ( ; polylist; polylist = polylist->getNext() )
+ polylist->CorrectBase( this, numsourcevertices, numsourcefaces, numpolygons );
+ numpolygons += mergeobj->numpolygons;
+ numpolygons_in += mergeobj->numpolygons_in;
+ // merge polygon lists
+ polygonlist.MergeLists( &mergeobj->polygonlist );
+ } else {
+ // correct all polygons contained in bsp tree
+ mergeobj->bsptree->CorrectPolygonBases( this, numsourcevertices, numsourcefaces, numbsppolygons );
+ numbsppolygons += mergeobj->numbsppolygons;
+ numpolygons_in += mergeobj->numpolygons_in;
+
+ //NOTE:
+ // the bsp trees themselves are not merged! no polygonlist is
+ // copied over, since it is empty. the bsp trees have to be
+ // merged somewhere else, to take over the polygons and the
+ // bsp tree structure!
+ }
+
+ } else {
+
+ //NOTE:
+ // this is the merging code that assumes that many vertices
+ // in the two objects are potentially exactly identical.
+ // therefore, the vertexlists are checked for doublets and
+ // vertex indexes contained in polygons are corrected thusly.
+ // since this normally is not necessary, the code is brute
+ // force, yielding quadratic performance!!
+ // however, in vrml files this may be a frequent case! if
+ // a connected object is saved as separate objects (e.g., to
+ // use more than one texture) the entire vertex list is often
+ // instanced via USE at each of these objects. this yields
+ // many objects with identical vertex lists.
+
+ // merge vertex lists and alloc index mapping table
+ int numsourcevertices = vertexlist.getNumElements();
+ int nummergevertices = mergeobj->vertexlist.getNumElements();
+ int numinsertvertices = 0;
+ int numinsertoriginal = 0;
+ int *indxmap = new int[ nummergevertices ];
+ int i = 0;
+ int j = 0;
+ for ( i = 0; i < nummergevertices; i++ ) {
+ for ( j = 0; j < numsourcevertices; j++ )
+ if ( vertexlist[ j ] == mergeobj->vertexlist[ i ] ) {
+ indxmap[ i ] = j;
+ break;
+ }
+ if ( j == numsourcevertices ) {
+ indxmap[ i ] = vertexlist.getNumElements();
+ vertexlist.AddVertex( mergeobj->vertexlist[ i ] );
+ numinsertvertices++;
+ if ( i < mergeobj->numvertices_in )
+ numinsertoriginal++;
+ }
+ }
+ numvertices += numinsertvertices;
+ numvertices_in += numinsertoriginal;
+
+ // merge face lists
+ int numsourcefaces = facelist.getNumElements();
+ int nummergefaces = mergeobj->facelist.getNumElements();
+ for ( i = 0; i < nummergefaces; i++ ) {
+ Face& mergeface = mergeobj->facelist[ i ];
+ mergeface.setId( mergeface.getId() + numsourcefaces );
+ facelist.AddElement( mergeface );
+ }
+ numfaces += nummergefaces;
+ numfaces_in += mergeobj->numfaces_in;
+
+ // correct all polygons
+ if ( !mergeobj->BSPTreeAvailable() ) {
+ // correct entire polygon list
+ Polygon *polylist = mergeobj->polygonlist.FetchHead();
+ for ( ; polylist; polylist = polylist->getNext() )
+ polylist->CorrectBaseByTable( this, indxmap, numsourcefaces, numpolygons );
+ numpolygons += mergeobj->numpolygons;
+ numpolygons_in += mergeobj->numpolygons_in;
+ // merge polygon lists
+ polygonlist.MergeLists( &mergeobj->polygonlist );
+ } else {
+ // correct all polygons contained in bsp tree
+ mergeobj->bsptree->CorrectPolygonBasesByTable( this, indxmap, numsourcefaces, numbsppolygons );
+ numbsppolygons += mergeobj->numbsppolygons;
+ numpolygons_in += mergeobj->numpolygons_in;
+ }
+
+ // free vertex index map
+ delete indxmap;
+ }
+
+ // merge texture lists
+ int numsourcetextures = texturelist.getNumElements();
+ int nummergetextures = mergeobj->texturelist.getNumElements();
+ int i = 0;
+ int j = 0;
+ for ( i = 0; i < nummergetextures; i++ ) {
+ //NOTE:
+ // terribly inefficient implementation. normally, number of
+ // textures should be very low. if this is not the case this
+ // may take considerable processing time!
+ for ( j = 0; j < numsourcetextures; j++ )
+ if ( strcmp( texturelist[ j ].getName(), mergeobj->texturelist[ i ].getName() ) == 0 )
+ break;
+ if ( j == numsourcetextures )
+ texturelist.AddElement( mergeobj->texturelist[ i ] );
+ }
+ numtextures += nummergetextures;
+
+ //NOTE:
+ // mappinglists need not be merged, since they are only temporarily
+ // used before complete face definitions are built. actual texture
+ // parameterization is a part of each face!
+
+ // add up other counts
+ numcorrespondences += mergeobj->numcorrespondences;
+ numnormals += mergeobj->numnormals;
+ numtexmappedfaces += mergeobj->numtexmappedfaces;
+ numtracevertices += mergeobj->numtracevertices;
+ nummultvertices += mergeobj->nummultvertices;
+ numsplitquadrilaterals += mergeobj->numsplitquadrilaterals;
+ numpolygons_before_bsp += mergeobj->numpolygons_before_bsp;
+ }
+
+}
+
+
+// collapse entire list of BspObjects into this object ------------------------
+//
+void BspObject::CollapseObjectList()
+{
+ //NOTE:
+ // this function only works if no bsp trees have been built yet!
+ // if bsp trees have already been built, ObjectBSPNode::CreateMergedBSPTree()
+ // may be used to merge all objects and bsp trees into one.
+
+ // exit if bsp tree available
+ if ( BspTreeAvailable() )
+ return;
+ BspObject *curobj = NULL;
+ curobj = getNext();
+ // merge all subsequent objects into this object
+ for ( curobj = curobj; curobj; curobj = curobj->getNext() ) {
+ MergeObjects( curobj );
+
+ // invalidate other object's polygonlist
+ curobj->getPolygonList().InvalidateList();
+
+ //NOTE:
+ // the polygon list must be invalidated prior to deletion
+ // because the actual polygons are now part of this object
+ // and therefore still in use!
+ }
+
+ // delete all objects that have been merged into this object
+ delete next;
+ next = NULL;
+
+ UpdateAttributeNumbers();
+}
+
+
+// static flags ---------------------------------------------------------------
+//
+int BspObject::check_vertex_doublets_on_merge = TRUE;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BspObject.h b/tool_src/BspLib/BspObject.h
new file mode 100644
index 0000000..c2dfdd8
--- /dev/null
+++ b/tool_src/BspLib/BspObject.h
@@ -0,0 +1,258 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspObject.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPOBJECT_H_
+#define _BSPOBJECT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+#include "Chunk.h"
+#include "Face.h"
+#include "Mapping.h"
+#include "PolygonList.h"
+#include "BSPTree.h"
+#include "Texture.h"
+#include "Transform3.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+class BoundingBox;
+
+
+// base class for BspObject providing data members ----------------------------
+//
+class BspObjectInfo {
+
+ friend class BspObject;
+
+private:
+ BspObjectInfo();
+ ~BspObjectInfo() { }
+
+public:
+ int getNumVertices() const { return numvertices; }
+ int getNumPolygons() const { return numpolygons; }
+ int getNumFaces() const { return numfaces; }
+
+ int getInputVertices() const { return numvertices_in; }
+ int getInputPolygons() const { return numpolygons_in; }
+ int getInputFaces() const { return numfaces_in; }
+
+ int getBspPolygons() const { return numbsppolygons; }
+ int getPreBspPolygons() const { return numpolygons_before_bsp; }
+
+ int getNumTextures() const { return numtextures; }
+ int getNumMappings() const { return numcorrespondences; }
+ int getNumNormals() const { return numnormals; }
+ int getNumTexturedFaces() const { return numtexmappedfaces; }
+
+ int getNumTraceVertices() const { return numtracevertices; }
+ int getNumMultiVertices() const { return nummultvertices; }
+ int getNumSplitQuads() const { return numsplitquadrilaterals; }
+
+protected:
+ int numvertices; // number of vertices in vertexlist
+ int numpolygons; // number of polygons in polygonlist
+ int numfaces; // number of faces in facelist
+ int numtextures; // number of textures in texturelist
+ int numcorrespondences; // number of correspondences in mappinglist
+
+ int numnormals; // number of faces with valid normals
+ int numtexmappedfaces; // number of texture mapped faces
+
+ int numvertices_in; // copy of numvertices directly after parse
+ int numpolygons_in; // copy of numpolygons directly after parse
+ int numfaces_in; // copy of numfaces directly after parse
+
+ int numbsppolygons; // number of polygons contained in bsp tree
+ int numpolygons_before_bsp; // copy of numpolygons before start of bsp compilation
+
+ int numtracevertices; // number of vertices for edge tracing
+ int nummultvertices; // number of multiply contained vertices
+ int numsplitquadrilaterals; // number of quadrilaterals split into triangles
+};
+
+
+// class describing a generic 3-D object in BspLib ----------------------------
+//
+class BspObject : public BspObjectInfo, public virtual SystemIO {
+
+ friend class BoundingBox;
+ friend class BspObjectListRep;
+ friend class Face;
+ friend class ObjectBSPNode;
+ friend class Polygon;
+
+ friend class VrmlFile;
+
+public:
+ BspObject();
+ ~BspObject() { delete objectname; delete next; }
+
+ BspObject( const BspObject& copyobj );
+ BspObject& operator =( const BspObject& copyobj );
+
+ // merge another BspObject into this object. this renumbers the other
+ // object's vertices, faces, polygons, and vertexindexes in polygons
+ void MergeObjects( BspObject *mergeobj );
+
+ void CollapseObjectList(); // collapse entire list into this object
+
+ BoundingBox* BuildBoundingBoxList(); // build a list of bounding boxes
+
+ BSPNode* BuildBSPTree(); // build bsp tree from polygon list
+ BSPNode* BuildBSPTreeFromFlat(); // build bsp tree from flat representation
+
+ int BspTreeAvailable(); // any bsp tree available?
+ int BSPTreeAvailable(); // linked bsp tree available?
+ int BSPTreeFlatAvailable(); // flat bsp tree available?
+
+ // processing functions (typically passed through to primitives)
+ void CalcBoundingBoxes(); // operates on bsp tree only
+ void CalcSeparatorPlanes(); // operates on bsp tree only
+ void CheckEdges(); // operates on bsp tree only
+ void CheckPolygonPlanes(); // operates on polygon list only
+ void CheckVertices( int verbose ); // scans entire vertex list
+ void CalcPlaneNormals(); // operates on polygon list only
+ void CheckParsedData(); // some consistency checks
+ void UpdateAttributeNumbers(); // calc length of lists
+
+ int ConvertColorIndexesToRGB( char *palette, int changemode );
+
+ // return bounding box extents for this object
+ void CalcBoundingBox( Vertex3& minvertex, Vertex3& maxvertex );
+
+ // display some object statistics
+ void DisplayStatistics();
+
+ // ASCII output functions that have to be implemented by
+ // derived ObjectXXXFormat classes.
+ // must not be pure virtual!
+ virtual int WriteVertexList( FileAccess& fp ) { return FALSE; }
+ virtual int WritePolygonList( FileAccess& fp ) { return FALSE; }
+ virtual int WriteFaceList( FileAccess& fp ) { return FALSE; }
+ virtual int WriteFaceProperties( FileAccess& fp ) { return FALSE; }
+ virtual int WriteTextureList( FileAccess& fp ) { return FALSE; }
+ virtual int WriteMappingList( FileAccess& fp ) { return FALSE; }
+ virtual int WriteNormals( FileAccess& fp ) { return FALSE; }
+ virtual int WriteBSPTree( FileAccess& fp ) { return FALSE; }
+
+ // return contained objects
+ VertexChunk& getVertexList() { return vertexlist; }
+ PolygonList& getPolygonList() { return polygonlist; }
+ FaceChunk& getFaceList() { return facelist; }
+ TextureChunk& getTextureList() { return texturelist; }
+ MappingChunk& getMappingList() { return mappinglist; }
+ BSPTree& getBSPTree() { return bsptree; }
+ BSPTreeFlat& getBSPTreeFlat() { return bsptreeflat; }
+
+ // get/set object's name-string
+ char* getObjectName() const { return objectname; }
+ void setObjectName( char *name );
+
+ // get/set object's local transformation
+ Vertex3 getCenterInWorldSpace() const { return objecttrafo.FetchTranslation(); }
+ Transform3 getObjectTransformation() const { return objecttrafo; }
+ void setObjectTransformation( const Transform3& ot ) { objecttrafo = ot; }
+
+ // scale entire object (all vertices)
+ void ApplyScale( double scalefac );
+
+ // apply translation to all coordinates and set center to (0,0,0)
+ void ApplyCenter();
+
+ // apply transformation matrix and set to identity afterwards
+ void ApplyTransformation();
+
+ // return next object in list
+ BspObject* getNext() const { return next; }
+
+private:
+ void InconsistencyError( const char *err );
+
+public:
+ static int getEliminateDoubletsOnMergeFlag() { return check_vertex_doublets_on_merge; }
+ static void setEliminateDoubletsOnMergeFlag( int flag ) { check_vertex_doublets_on_merge = flag; }
+
+private:
+ static int check_vertex_doublets_on_merge;
+
+protected:
+ // contained objects
+ VertexChunk vertexlist; // list of vertices
+ PolygonList polygonlist; // list of polygons
+ FaceChunk facelist; // list of faces
+ TextureChunk texturelist; // list of textures
+ MappingChunk mappinglist; // list of mappings
+ BSPTree bsptree; // linked bsp tree
+ BSPTreeFlat bsptreeflat; // flat bsp tree
+ Transform3 objecttrafo; // attached transformation
+
+ // object's name if any defined
+ char* objectname;
+
+ // pointer to next object in list
+ BspObject* next;
+};
+
+// copy constructor -----------------------------------------------------------
+inline BspObject::BspObject( const BspObject& copyobj ) :
+ BspObjectInfo( copyobj ),
+ vertexlist( copyobj.vertexlist ),
+ polygonlist( copyobj.polygonlist ),
+ facelist( copyobj.facelist ),
+ texturelist( copyobj.texturelist ),
+ mappinglist( copyobj.mappinglist ),
+ bsptree( copyobj.bsptree ),
+ bsptreeflat( copyobj.bsptreeflat ),
+ objecttrafo( copyobj.objecttrafo )
+{
+ // copy object's name
+ objectname = NULL;
+ setObjectName( copyobj.objectname );
+
+ // unlink tail of list
+ next = NULL;
+}
+
+// assignment operator --------------------------------------------------------
+inline BspObject& BspObject::operator =( const BspObject& copyobj )
+{
+ if ( &copyobj != this ) {
+
+ // copy info part
+ *(BspObjectInfo *)this = copyobj;
+
+ // copy contained objects
+ vertexlist = copyobj.vertexlist;
+ polygonlist = copyobj.polygonlist;
+ facelist = copyobj.facelist;
+ texturelist = copyobj.texturelist;
+ mappinglist = copyobj.mappinglist;
+ bsptree = copyobj.bsptree;
+ bsptreeflat = copyobj.bsptreeflat;
+ objecttrafo = copyobj.objecttrafo;
+
+ // copy object's name
+ setObjectName( copyobj.objectname );
+
+ // unlink tail of list
+ next = NULL;
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPOBJECT_H_
+
diff --git a/tool_src/BspLib/BspObjectList.cpp b/tool_src/BspLib/BspObjectList.cpp
new file mode 100644
index 0000000..604682b
--- /dev/null
+++ b/tool_src/BspLib/BspObjectList.cpp
@@ -0,0 +1,197 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BspObjectList.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspObjectList.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// create new (default constructed) BspObject and prepend it to list ----------
+//
+BspObject *BspObjectListRep::CreateNewObject()
+{
+ BspObject *temp = new BspObject;
+ temp->next = list;
+ list = temp;
+ return list;
+}
+
+
+// insert existing BspObject at head of list ----------------------------------
+//
+BspObject *BspObjectListRep::InsertObject( BspObject *obj )
+{
+ if ( obj != NULL ) {
+ obj->next = list;
+ list = obj;
+ }
+ return obj;
+}
+
+
+// build a list of bounding boxes containing all objects of list --------------
+//
+BoundingBox *BspObjectListRep::BuildBoundingBoxList()
+{
+ return ( list ? list->BuildBoundingBoxList() : NULL );
+}
+
+
+// count number of objects in list --------------------------------------------
+//
+int BspObjectListRep::CountListObjects()
+{
+ int count = 0;
+ for ( BspObject *scan = list; scan; scan = scan->getNext() )
+ count++;
+ return count;
+}
+
+
+// prepare object bsp tree as secondary data structure ------------------------
+//
+int BspObjectListRep::PrepareObjectBSPTree( ObjectBSPTree& objbsptree )
+{
+ if ( list != NULL ) {
+ // create list of bounding boxes with contained objects
+ BoundingBox *bboxlist = BuildBoundingBoxList();
+ // partition space containing bounding boxes (list becomes invalid!)
+ objbsptree.InitTree( bboxlist->PartitionSpace() );
+ // create new object list, object bsp tree becomes secondary data structure
+ list = objbsptree->CreateObjectList();
+ }
+ return ( list != NULL );
+}
+
+
+// merge object bsp tree into a single object and attached bsp tree -----------
+//
+int BspObjectListRep::MergeObjectBSPTree( ObjectBSPTree& objbsptree )
+{
+ //NOTE:
+ // it is imperative that the passed in ObjectBSPTree really
+ // contains all BspObjects of this list! if this is not the
+ // case the list will simply be overwritten with a single-element
+ // list containing the aggregate object of all nodes of the
+ // passed in ObjectBSPTree. the original list nodes will be lost!
+
+ // create list consisting only of the merged object
+ list = objbsptree->CreateMergedBSPTree();
+
+ // delete all BspObjects contained in tree since they are now
+ // unnecessary. (their data is contained in the merged object.)
+ objbsptree->DeleteNodeBspObjects();
+ objbsptree.KillTree();
+
+ return ( list != NULL );
+}
+
+
+// collapse entire list of BspObjects into head of list -----------------------
+//
+int BspObjectListRep::CollapseObjectList()
+{
+ if ( list != NULL )
+ list->CollapseObjectList();
+ return ( list != NULL );
+}
+
+
+// process all objects contained in list --------------------------------------
+//
+int BspObjectListRep::ProcessObjects( int flags )
+{
+ // scan entire list
+ for ( BspObject *bspobject = list; bspobject; bspobject = bspobject->getNext() ) {
+
+ // apply transformations directly to vertices
+ if ( flags & BspObjectList::APPLY_TRANSFORMATIONS ) {
+ bspobject->ApplyTransformation();
+ }
+
+ // calculate plane normals for planes of all polygons
+ if ( flags & BspObjectList::CALC_PLANE_NORMALS )
+ bspobject->CalcPlaneNormals();
+
+ // build linked bsp tree from flat representation
+ if ( flags & BspObjectList::BUILD_FROM_FLAT ) {
+ if ( bspobject->BuildBSPTreeFromFlat() )
+ bspobject->bsptree->NumberBSPNodes( bspobject->numbsppolygons );
+ continue; // no other processing allowed
+ }
+
+ //TODO:
+ // 1. vertices zusammenlegen: MergeVertices()
+ // 2. ueberfluessige edges entfernen: CullNullEdges()
+ // 3. t vertices entfernen: EliminateTVertices()
+ // 4. faces zusammenlegen: MergeFaces()
+
+ // MergeFaces(): nur fuer 3d-studio tri-mesh!!
+ // fuer jedes triangle werden alle anderen gescannt, ob sie eine
+ // edge teilen. falls ja, wird fuer den dritten punkt geprueft, ob er
+ // in der selben ebene liegt. ja --> triangle to quadrilateral merge.
+ // der umlaufsinn der vertex numerierung wird dahingehend geprueft, ob
+ // er konsistent mit dem ergebnis-quad ist.
+ // nein: warnmeldung und kein mergen!!
+
+ if ( flags & BspObjectList::MERGE_VERTICES ) {
+ }
+
+ if ( flags & BspObjectList::CULL_NULL_EDGES ) {
+ }
+
+ if ( flags & BspObjectList::ELIMINATE_T_VERTICES ) {
+ }
+
+ if ( flags & BspObjectList::MERGE_FACES ) {
+ }
+
+ // split (possibly hand edited) faces with vertices not in same plane
+ if ( flags & BspObjectList::CHECK_PLANES )
+ bspobject->CheckPolygonPlanes();
+
+ // compile bsp tree and number nodes
+ if ( flags & BspObjectList::BUILD_BSP )
+ if ( bspobject->BuildBSPTree() )
+ bspobject->bsptree->NumberBSPNodes( bspobject->numbsppolygons );
+
+ // check for vertices with exact same coordinates
+ if ( flags & BspObjectList::CHECK_VERTICES )
+ bspobject->CheckVertices( TRUE );
+
+ // calc bounding boxes for all nodes
+ // operates on bsp tree only, so one has to be present!
+ if ( flags & BspObjectList::CALC_BOUNDING_BOXES )
+ bspobject->CalcBoundingBoxes();
+
+ // calc explicit separator planes for all nodes
+ // operates on bsp tree only, so one has to be present!
+ if ( flags & BspObjectList::CALC_SEPARATOR_PLANES )
+ bspobject->CalcSeparatorPlanes();
+
+ // check edges for t-vertices and eliminate them (insert trace vertices)
+ // operates on bsp tree only, so one has to be present!
+ if ( flags & BspObjectList::CHECK_EDGES )
+ bspobject->CheckEdges();
+
+ // display object and compilation statistics
+ if ( flags & BspObjectList::DISPLAY_STATS )
+ bspobject->DisplayStatistics();
+
+ // update attribute numbers, even if no statistics desired
+ bspobject->UpdateAttributeNumbers();
+ }
+
+ return TRUE;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BspObjectList.h b/tool_src/BspLib/BspObjectList.h
new file mode 100644
index 0000000..e4f8c17
--- /dev/null
+++ b/tool_src/BspLib/BspObjectList.h
@@ -0,0 +1,151 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspObjectList.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPOBJECTLIST_H_
+#define _BSPOBJECTLIST_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "ObjectBSPTree.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class for list of BspObject items (representation class) -------------------
+//
+class BspObjectListRep {
+
+ friend class BspObjectList;
+
+public:
+ BspObjectListRep() : ref_count( 0 ) { list = NULL; }
+ ~BspObjectListRep() { delete list; }
+
+ BspObject* CreateNewObject(); // prepend empty object to list
+ BspObject* InsertObject( BspObject *obj ); // insert existing object at head
+
+ BoundingBox* BuildBoundingBoxList(); // build a list of bounding boxes
+
+ int CountListObjects(); // count list objects
+
+ int PrepareObjectBSPTree( ObjectBSPTree& objbsptree );
+ int MergeObjectBSPTree( ObjectBSPTree& objbsptree );
+
+ int CollapseObjectList(); // collapse list into its head object
+
+ int ProcessObjects( int flags ); // various processing functions
+
+ int BspTreeAvailable() { return list ? list->BspTreeAvailable() : FALSE; }
+ int BSPTreeAvailable() { return list ? list->BSPTreeAvailable() : FALSE; }
+ int BSPTreeFlatAvailable() { return list ? list->BSPTreeFlatAvailable() : FALSE; }
+
+ BspObject* getListHead() const { return list; }
+
+private:
+ int ref_count; // number of references to this list
+ BspObject* list; // first element in list
+};
+
+
+// class for list of BspObject items (handle class) ---------------------------
+//
+class BspObjectList {
+
+public:
+
+ // object processing flags
+ enum {
+ CHECK_PLANES = 0x0001,
+ BUILD_BSP = 0x0002,
+ CHECK_VERTICES = 0x0004,
+ CHECK_EDGES = 0x0008,
+ BUILD_BSP_WITH_CHECKS = 0x000F,
+ DISPLAY_STATS = 0x0010,
+ BUILD_FROM_FLAT = 0x0020,
+ MERGE_VERTICES = 0x0040,
+ CULL_NULL_EDGES = 0x0080,
+ ELIMINATE_T_VERTICES = 0x0100,
+ MERGE_FACES = 0x0200,
+ CALC_PLANE_NORMALS = 0x0400,
+ CALC_BOUNDING_BOXES = 0x0800,
+ CALC_SEPARATOR_PLANES = 0x1000,
+ APPLY_TRANSFORMATIONS = 0x2000,
+ };
+
+public:
+ BspObjectList() { rep = new BspObjectListRep(); rep->ref_count = 1; }
+ ~BspObjectList() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ BspObjectList( const BspObjectList& copyobj );
+ BspObjectList& operator =( const BspObjectList& copyobj );
+
+ BspObject* CreateNewObject() { return rep->CreateNewObject(); }
+ BspObject* InsertObject( BspObject *obj ) { return rep->InsertObject( obj ); }
+
+ // create a list of bounding boxes containing a bounding box for each
+ // node in the list. user has to keep track of the list's head!
+ BoundingBox* BuildBoundingBoxList() { return rep->BuildBoundingBoxList(); }
+
+ int CountListObjects() { return rep->CountListObjects(); }
+
+ int PrepareObjectBSPTree( ObjectBSPTree& objbsptree ) { return rep->PrepareObjectBSPTree( objbsptree ); }
+ int MergeObjectBSPTree( ObjectBSPTree& objbsptree ) { return rep->MergeObjectBSPTree( objbsptree ); }
+
+ int CollapseObjectList() { return rep->CollapseObjectList(); }
+
+ // process entire list according to bitfield specifying desired processing
+ int ProcessObjects( int flags ) { return rep->ProcessObjects( flags ); }
+
+ // BSP tree of any representation available (linked or flat)?
+ int BspTreeAvailable() { return rep->BspTreeAvailable(); }
+ // linked BSP tree available?
+ int BSPTreeAvailable() { return rep->BSPTreeAvailable(); }
+ // flat BSP tree available?
+ int BSPTreeFlatAvailable() { return rep->BSPTreeFlatAvailable(); }
+
+ //NOTE:
+ // the previous functions actually return the state of the first BspObject
+ // in the list. if bsp trees have not been built through ProcessObjects()
+ // it is not guaranteed that the returned state holds for every object in
+ // the list! normally, list nodes should not be accessed separately, though.
+
+ // return pointer to first BspObject in list
+ BspObject* getListHead() { return rep->getListHead(); }
+
+private:
+ BspObjectListRep *rep;
+};
+
+// copy constructor for BspObjectList -----------------------------------------
+inline BspObjectList::BspObjectList( const BspObjectList& copyobj )
+{
+ rep = copyobj.rep; // shallow copy
+ rep->ref_count++; // with reference counting
+}
+
+// assignment operator for BspObjectList --------------------------------------
+inline BspObjectList& BspObjectList::operator =( const BspObjectList& copyobj )
+{
+ if ( &copyobj != this ) {
+ // old reference is overwritten
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep; // shallow copy
+ rep->ref_count++; // with reference counting
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPOBJECTLIST_H_
+
diff --git a/tool_src/BspLib/BspOutput.cpp b/tool_src/BspLib/BspOutput.cpp
new file mode 100644
index 0000000..b86fc9f
--- /dev/null
+++ b/tool_src/BspLib/BspOutput.cpp
@@ -0,0 +1,108 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BspOutput.cpp
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspOutput.h"
+#include "BspObject.h"
+#include "BspTool.h"
+#include "ObjectBspFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct BspOutput object -------------------------------------------------
+//
+BspOutput::BspOutput( BspObjectList objectlist, const char *filename ) :
+ SingleOutput( objectlist, BspTool::ChangeExtension( filename, BSP_FILE_EXTENSION ) )
+{
+}
+
+
+// construct BspOutput object using an InputData3D object ---------------------
+//
+BspOutput::BspOutput( const InputData3D& inputdata ) :
+ SingleOutput( inputdata.getObjectList(),
+ BspTool::ChangeExtension( inputdata.getFileName(), BSP_FILE_EXTENSION ) )
+{
+ // get pointer to "real" input object
+ InputData3D *inputobj = inputdata.getRealObject();
+
+ // try to isolate the BspFormat part of the input object
+ BspFormat *bspformat = dynamic_cast<BspFormat*>(inputobj);
+
+ // copy over if cast succeeded
+ if ( bspformat != NULL ) {
+
+ *(BspFormat *)this = *bspformat;
+
+ } else {
+
+ // try to isolate the SingleFormat part of the input object
+ SingleFormat *singleformat = dynamic_cast<SingleFormat*>(inputobj);
+
+ // copy over if cast succeeded
+ if ( singleformat != NULL )
+ *(SingleFormat *)this = *singleformat;
+ }
+}
+
+
+// write outputfile before destruction ----------------------------------------
+//
+BspOutput::~BspOutput()
+{
+ if ( m_output.Status() == SYSTEM_IO_OK )
+ WriteOutputFile();
+}
+
+
+// assignment copies only the BspFormat part of the object --------------------
+//
+BspOutput& BspOutput::operator =( const BspOutput& copyobj )
+{
+ *(BspFormat *)this = copyobj;
+ return *this;
+}
+
+
+// write '.bsp' file for this object ------------------------------------------
+//
+int BspOutput::WriteOutputFile()
+{
+ sprintf( line, "Writing compiled object data to \"%s\"...\n", (const char *) m_filename );
+ InfoMessage( line );
+
+ sprintf( line, "%s\n\n", BSP_SIGNATURE_1_1 );
+ m_output.WriteLine( line );
+
+ // write bsplib banner to file and init output data
+ SingleOutput::InitOutput();
+
+ // create 3-D object knowing about '.bsp' format
+ ObjectBspFormat obj( *m_baseobject, *this );
+
+ // write attribute lists
+ obj.WriteVertexList( m_output );
+ obj.WritePolygonList( m_output );
+ obj.WriteFaceList( m_output );
+ obj.WriteNormals( m_output );
+ obj.WriteFaceProperties( m_output );
+ obj.WriteMappingList( m_output );
+ obj.WriteBSPTree( m_output );
+ obj.WriteTextureList( m_output );
+
+ // write common part
+ SingleOutput::WriteOutputFile();
+
+ return m_output.Status();
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BspOutput.h b/tool_src/BspLib/BspOutput.h
new file mode 100644
index 0000000..877fead
--- /dev/null
+++ b/tool_src/BspLib/BspOutput.h
@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspOutput.h
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPOUTPUT_H_
+#define _BSPOUTPUT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspFormat.h"
+#include "BspInput.h"
+#include "SingleOutput.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file output class for bsp format files -------------------------------------
+//
+class BspOutput : public BspFormat, public SingleOutput {
+
+public:
+ BspOutput( BspObjectList objectlist, const char *filename );
+ BspOutput( const InputData3D& inputdata );
+ ~BspOutput();
+
+ BspOutput& operator =( const BspOutput& copyobj );
+
+public:
+ int WriteOutputFile();
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPOUTPUT_H_
+
diff --git a/tool_src/BspLib/BspTool.cpp b/tool_src/BspLib/BspTool.cpp
new file mode 100644
index 0000000..23bcb8d
--- /dev/null
+++ b/tool_src/BspLib/BspTool.cpp
@@ -0,0 +1,68 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: BspTool.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspTool.h"
+
+// flags
+#define STRIP_PATH
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// create new string with altered extension -----------------------------------
+//
+String BspTool::ChangeExtension( const char *filename, const char *extension )
+{
+ if ( ( filename == NULL ) || ( extension == NULL ) )
+ return String( NULL );
+
+ int len = strlen( filename );
+ int pos = len;
+ char *name = NULL;
+ const char *scan = filename + pos;
+
+ while ( ( --pos > 0 ) && ( *--scan != '.' ) ) ;
+
+ if ( pos > 0 ) {
+ // change extension if there was an extension
+ name = new char[ pos + strlen( extension ) + 1 ];
+ strncpy( name, filename, pos );
+ strcpy( name + pos, extension );
+ } else {
+ // append new extension if there was no extension
+ name = new char[ len + strlen( extension ) + 1 ];
+ strcpy( name, filename );
+ strcpy( name + len, extension );
+ }
+
+#ifdef STRIP_PATH
+ String ret( SkipPath( name ) );
+#else
+ String ret( name );
+#endif
+
+ delete name;
+ return ret;
+}
+
+
+// create filename without path -----------------------------------------------
+//
+const String BspTool::SkipPath( const char *fullname )
+{
+ const char *scan = fullname + strlen( fullname ) - 1;
+ while ( ( *scan != '\\' ) && ( *scan != ':' ) && ( scan >= fullname ) )
+ scan--;
+ return String( scan + 1 );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/BspTool.h b/tool_src/BspLib/BspTool.h
new file mode 100644
index 0000000..607592e
--- /dev/null
+++ b/tool_src/BspLib/BspTool.h
@@ -0,0 +1,34 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: BspTool.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _BSPTOOL_H_
+#define _BSPTOOL_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// BspTool contains miscellaneous helper functions ----------------------------
+//
+class BspTool {
+
+public:
+ static String ChangeExtension( const char *filename, const char *extension );
+ static const String SkipPath( const char *name );
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _BSPTOOL_H_
+
diff --git a/tool_src/BspLib/COPYING b/tool_src/BspLib/COPYING
new file mode 100644
index 0000000..bf50f20
--- /dev/null
+++ b/tool_src/BspLib/COPYING
@@ -0,0 +1,482 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/tool_src/BspLib/Chunk.h b/tool_src/BspLib/Chunk.h
new file mode 100644
index 0000000..db4fa62
--- /dev/null
+++ b/tool_src/BspLib/Chunk.h
@@ -0,0 +1,280 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Chunk.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _CHUNK_H_
+#define _CHUNK_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+
+
+// if this flag is set storage is increased by using lists
+//#define EXPAND_STORAGE_WITH_LISTS
+
+// if this flag is set storage is always increased two-fold
+#define EXPAND_EXPONENTIALLY
+
+// if this flag is set assignment operators for elements are not invoked
+//#define IGNORE_ELEMENT_ASSIGNMENT_OPERATORS
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// added for Visual C++ 6.0
+template<class T> class Chunk;
+
+
+// template for simple chunk class (actual representation) --------------------
+//
+template<class T>
+class ChunkRep : public virtual SystemIO {
+
+ friend class Chunk<T>;
+
+ // error identifiers
+ enum {
+ E_INVALIDINDX
+ };
+
+ void Error( int err ) const;
+
+private:
+ ChunkRep( int chunksize = 0 );
+ ~ChunkRep();
+
+ int AddElement( const T& element );
+ T& FetchElement( int index );
+
+ int getNumElements() const;
+
+private:
+ int ref_count;
+ int numelements;
+ int maxnumelements;
+ T* elements;
+ ChunkRep* next;
+
+ static const int CHUNK_SIZE;
+};
+
+
+// create new chunk -----------------------------------------------------------
+//
+template<class T>
+ChunkRep<T>::ChunkRep( int chunksize ) : ref_count( 0 )
+{
+ int challocsize = chunksize > 0 ? chunksize : CHUNK_SIZE;
+ elements = new T[ challocsize ];
+ maxnumelements = challocsize;
+ numelements = 0;
+ next = NULL;
+}
+
+
+// destroy list of chunks recursively -----------------------------------------
+//
+template<class T>
+ChunkRep<T>::~ChunkRep()
+{
+ delete[] elements;
+ delete next;
+}
+
+
+// error message handler ------------------------------------------------------
+//
+template<class T>
+void ChunkRep<T>::Error( int err ) const
+{
+ {
+ StrScratch message;
+ sprintf( message, "***ERROR*** in object of a class of template Chunk" );
+
+ switch ( err ) {
+
+ case E_INVALIDINDX:
+ sprintf( message + strlen( message ), ": [Invalid index]" );
+ break;
+ }
+
+ ErrorMessage( message );
+ }
+
+ HandleCriticalError();
+}
+
+
+// fetch element corresponding to specific index ------------------------------
+//
+template<class T>
+T& ChunkRep<T>::FetchElement( int index )
+{
+
+#ifdef EXPAND_STORAGE_WITH_LISTS
+
+ ChunkRep *vlist = this;
+ while ( ( vlist != NULL ) && ( index >= vlist->numelements ) ) {
+ index -= vlist->numelements;
+ vlist = vlist->next;
+ }
+
+ if ( vlist == NULL )
+ Error( E_INVALIDINDX );
+
+ // return element
+ return vlist->elements[ index ];
+
+#else
+
+ if ( index >= numelements )
+ Error( E_INVALIDINDX );
+
+ // return element
+ return elements[ index ];
+
+#endif
+
+}
+
+
+// insert element into chunk, return index ------------------------------------
+//
+template<class T>
+int ChunkRep<T>::AddElement( const T& element )
+{
+
+#ifdef EXPAND_STORAGE_WITH_LISTS
+
+ // if space in head-chunk insert element directly
+ if ( numelements < maxnumelements ) {
+ elements[ numelements ] = element;
+ return numelements++;
+
+ } else {
+
+ int numskipped = numelements;
+ ChunkRep *vlist = this;
+
+ // scan until non-full chunk found
+ while ( ( vlist->next != NULL ) && ( vlist->next->numelements == vlist->next->maxnumelements ) ) {
+ vlist = vlist->next;
+ numskipped += vlist->numelements;
+ }
+
+ // insert new chunk if all existing are full
+ if ( vlist->next == NULL ) {
+
+#ifdef EXPAND_EXPONENTIALLY
+ vlist->next = new ChunkRep( vlist->maxnumelements * 2 );
+#else
+ vlist->next = new ChunkRep;
+#endif
+ }
+
+ // insert new element
+ vlist->next->elements[ vlist->next->numelements ] = element;
+ return vlist->next->numelements++ + numskipped;
+ }
+
+#else
+
+ // expand storage if necessary
+ if ( numelements == maxnumelements ) {
+
+#ifdef EXPAND_EXPONENTIALLY
+ maxnumelements *= 2;
+#else
+ maxnumelements += CHUNK_SIZE;
+#endif
+ T *temp = new T[ maxnumelements ];
+
+#ifdef IGNORE_ELEMENT_ASSIGNMENT_OPERATORS
+ memcpy( temp, elements, numelements * sizeof( T ) );
+#else
+ for ( int i = 0; i < numelements; i++ )
+ temp[ i ] = elements[ i ];
+#endif
+ delete[] elements;
+ elements = temp;
+ }
+
+ elements[ numelements ] = element;
+ return numelements++;
+
+#endif
+
+}
+
+
+// return number of elements in entire chunk ----------------------------------
+//
+template<class T>
+int ChunkRep<T>::getNumElements() const
+{
+ int num = 0;
+ for ( const ChunkRep *vlist = this; vlist; vlist = vlist->next )
+ num += vlist->numelements;
+ return num;
+}
+
+
+// template for simple chunk class (handle class) -----------------------------
+//
+template<class T>
+class Chunk {
+
+public:
+ Chunk( int chunksize = 0 ) { rep = new ChunkRep<T>( chunksize ); rep->ref_count = 1; }
+ ~Chunk() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ Chunk( const Chunk& copyobj );
+ Chunk& operator =( const Chunk& copyobj );
+
+ T& operator []( int index ) { return rep->FetchElement( index ); }
+ T& FetchElement( int index ) { return rep->FetchElement( index ); }
+ int AddElement( const T& element ) { return rep->AddElement( element ); }
+
+ int getNumElements() const { return rep->getNumElements(); }
+
+private:
+ ChunkRep<T>* rep;
+};
+
+
+// copy constructor for a Chunk -----------------------------------------------
+//
+template<class T>
+Chunk<T>::Chunk( const Chunk<T>& copyobj )
+{
+ rep = copyobj.rep;
+ rep->ref_count++;
+}
+
+
+// assignment operator for a Chunk --------------------------------------------
+//
+template<class T>
+Chunk<T>& Chunk<T>::operator =( const Chunk<T>& copyobj )
+{
+ if ( &copyobj != this ) {
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep;
+ rep->ref_count++;
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _CHUNK_H_
+
diff --git a/tool_src/BspLib/EpsAreas.cpp b/tool_src/BspLib/EpsAreas.cpp
new file mode 100644
index 0000000..8f70803
--- /dev/null
+++ b/tool_src/BspLib/EpsAreas.cpp
@@ -0,0 +1,28 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: EpsAreas.cpp
+//
+// Copyright (c) 1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "BspLibDefs.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// epsilon area specifications ------------------------------------------------
+//
+double EpsAreas::eps_scalarproduct = 1e-7;
+double EpsAreas::eps_planethickness = 1e-7;
+double EpsAreas::eps_vanishdenominator = 1e-7;
+double EpsAreas::eps_vanishcomponent = 1e-7;
+double EpsAreas::eps_pointonline = 1e-5;
+double EpsAreas::eps_pointonlineseg = 1e-4;
+double EpsAreas::eps_vertexmergearea = 1e-4;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Face.cpp b/tool_src/BspLib/Face.cpp
new file mode 100644
index 0000000..4e529e4
--- /dev/null
+++ b/tool_src/BspLib/Face.cpp
@@ -0,0 +1,352 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Face.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Face.h"
+#include "Chunk.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// copy constructor for Face --------------------------------------------------
+//
+Face::Face( const Face& copyobj )
+{
+ faceid = copyobj.faceid;
+ facecolor_indx = copyobj.facecolor_indx;
+ facecolor_rgba = copyobj.facecolor_rgba;
+ shadingtype = copyobj.shadingtype;
+ colortype = copyobj.colortype;
+
+ faceplane = copyobj.faceplane ? new Plane( *copyobj.faceplane ) : NULL;
+ facematerial = copyobj.facematerial ? new Material( *copyobj.facematerial ) : NULL;
+ facemapping = copyobj.facemapping ? new TriMapping( *copyobj.facemapping ) : NULL;
+ texturename = copyobj.texturename ? new char[ strlen( copyobj.texturename ) + 1 ] : NULL;
+
+ if ( texturename != NULL )
+ strcpy( texturename, copyobj.texturename );
+}
+
+
+// assignment operator for Face -----------------------------------------------
+//
+Face& Face::operator =( const Face& copyobj )
+{
+ if ( &copyobj != this ) {
+ faceid = copyobj.faceid;
+ facecolor_indx = copyobj.facecolor_indx;
+ facecolor_rgba = copyobj.facecolor_rgba;
+ shadingtype = copyobj.shadingtype;
+ colortype = copyobj.colortype;
+
+ delete faceplane;
+ delete facematerial;
+ delete facemapping;
+ delete texturename;
+
+ faceplane = copyobj.faceplane ? new Plane( *copyobj.faceplane ) : NULL;
+ facematerial = copyobj.facematerial ? new Material( *copyobj.facematerial ) : NULL;
+ facemapping = copyobj.facemapping ? new TriMapping( *copyobj.facemapping ) : NULL;
+ texturename = copyobj.texturename ? new char[ strlen( copyobj.texturename ) + 1 ] : NULL;
+
+ if ( texturename != NULL )
+ strcpy( texturename, copyobj.texturename );
+ }
+ return *this;
+}
+
+
+// set name of texture for this face ------------------------------------------
+//
+void Face::setTextureName( const char *tname )
+{
+ delete texturename;
+ texturename = tname ? new char[ strlen( tname ) + 1 ] : NULL;
+ if ( texturename != NULL )
+ strcpy( texturename, tname );
+ colortype = no_col;
+}
+
+
+// calculate face's plane (normal and offset) and attach it -------------------
+//
+void Face::CalcPlane( const Vertex3& vertex1, const Vertex3& vertex2, const Vertex3& vertex3 )
+{
+ if ( faceplane && faceplane->PlaneValid() )
+ return;
+ if ( faceplane && faceplane->NormalValid() ) {
+ // if normal already valid only recalculate offset
+ faceplane->CalcPlaneOffset( vertex1 );
+ return;
+ }
+ // calculate completely new plane
+ delete faceplane;
+ faceplane = new Plane( vertex1, vertex2, vertex3 );
+
+ if ( !faceplane->PlaneValid() ) {
+ ErrorMessage( "\n***ERROR*** Collinear vertices encountered (BspLib::Face)." );
+ HandleCriticalError();
+ }
+}
+
+
+// attach normal after creating plane to store it in --------------------------
+//
+void Face::AttachNormal( const Vector3& normal )
+{
+ delete faceplane;
+ faceplane = new Plane( normal );
+}
+
+
+// attach face's plane calculated somewhere else ------------------------------
+//
+void Face::AttachPlane( Plane *plane )
+{
+ if ( plane != NULL ) {
+ delete faceplane;
+ faceplane = plane;
+ }
+}
+
+// attach material and set colortype accordingly ------------------------------
+//
+void Face::AttachMaterial( Material *mat )
+{
+ if ( mat != NULL ) {
+ delete facematerial;
+ facematerial = mat;
+ colortype = material_col;
+ }
+}
+
+
+// convert color index to RGB triplet using 256 color palette -----------------
+//
+int Face::ConvertColorIndexToRGB( char *palette, int changemode )
+{
+ if ( colortype == indexed_col ) {
+ byte *palentry = (byte *) palette + facecolor_indx * 3;
+ float oomax = 255.0f / 63.0f;
+ facecolor_rgba.R = (byte) ( palentry[ 0 ] * oomax );
+ facecolor_rgba.G = (byte) ( palentry[ 1 ] * oomax );
+ facecolor_rgba.B = (byte) ( palentry[ 2 ] * oomax );
+ facecolor_rgba.A = 255;
+ if ( changemode )
+ colortype = rgb_col;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// helper function ------------------------------------------------------------
+//
+inline void WriteRGBA( FILE *fp, const char *desc, ColorRGBA col )
+{
+ fprintf( fp, "%s %f %f %f %f ", desc,
+ col.R / 255.0f, col.G / 255.0f,
+ col.B / 255.0f, col.A / 255.0f );
+}
+
+
+// write face info to text-file -----------------------------------------------
+//
+void Face::WriteFaceInfo( FILE *fp ) const
+{
+ // write shading type specifier
+ fprintf( fp, "%s\t", prop_strings[ shadingtype & base_mask ] );
+
+ // write color if any attached and valid
+ if ( shadingtype & color_mask ) {
+ if ( colortype == indexed_col ) {
+ // write color index
+ fprintf( fp, "%s %d", color_strings[ colortype ], facecolor_indx );
+ } else if ( colortype == rgb_col ) {
+ // write (r,g,b) triplet
+ fprintf( fp, "%s %f %f %f", color_strings[ colortype ],
+ facecolor_rgba.R / 255.0f,
+ facecolor_rgba.G / 255.0f,
+ facecolor_rgba.B / 255.0f );
+ } else if ( colortype == material_col ) {
+ if ( facematerial != NULL ) {
+ fprintf( fp, "%s ", color_strings[ colortype ] );
+ ColorRGBA colquad;
+ colquad = facematerial->getAmbientColor();
+ WriteRGBA( fp, material_strings[ 0 ], colquad );
+ colquad = facematerial->getDiffuseColor();
+ WriteRGBA( fp, material_strings[ 1 ], colquad );
+ colquad = facematerial->getSpecularColor();
+ WriteRGBA( fp, material_strings[ 2 ], colquad );
+ colquad = facematerial->getEmissiveColor();
+ WriteRGBA( fp, material_strings[ 3 ], colquad );
+ fprintf( fp, "%s %f ", material_strings[ 4 ], facematerial->getShininess() );
+ fprintf( fp, "%s %f", material_strings[ 5 ], facematerial->getTransparency() );
+ } else {
+ fprintf( fp, "**INVALID MATERIAL**" );
+ }
+ }
+ }
+
+ // write texture info if any attached and valid
+ if ( shadingtype & texmap_mask ) {
+ if ( texturename != NULL )
+ fprintf( fp, "\"%s\"", texturename );
+ else
+ fprintf( fp, "**INVALID TEXTURE NAME**" );
+ }
+
+ // write face id as comment
+ fprintf( fp, "\t; %d\n", faceid + 1 );
+}
+
+
+// write facenormal to text-file ----------------------------------------------
+//
+void Face::WriteNormalInfo( FILE *fp ) const
+{
+ // write face's normal vector
+ if ( faceplane != NULL ) {
+ Vector3 normal = faceplane->getPlaneNormal();
+ fprintf( fp, "%f,\t%f,\t%f\t\t; %d\n",
+ normal.getX(),
+ normal.getY(),
+ normal.getZ(),
+ faceid + 1 );
+ } else {
+ // normal vector invalid (no plane attached)
+ fprintf( fp, "Normal of face #%d invalid.\n", faceid + 1 );
+ }
+}
+
+
+// write mapping info to text-file --------------------------------------------
+//
+void Face::WriteMappingInfo( FILE *fp ) const
+{
+ // write three point correspondences for mapping
+ if ( facemapping != NULL ) {
+ // write (x,y) domain
+ int i = 0 ;
+ for ( i = 0; i < 3; i++ ) {
+ Vector2 vertex = facemapping->getMapXY( i );
+ fprintf( fp, "%f,\t%f,\t%f\n",
+ vertex.getX(),
+ vertex.getY(),
+ vertex.getW() );
+ }
+ // write (u,v) domain
+ for ( i = 0; i < 3; i++ ) {
+ Vector2 vertex = facemapping->getMapUV( i );
+ fprintf( fp, "%f,\t%f,\t%f\n",
+ vertex.getX(),
+ vertex.getY(),
+ vertex.getW() );
+ }
+ fprintf( fp, "\n" );
+ } else {
+ // face mapping invalid (no affine mapping attached)
+ fprintf( fp, "Mapping for face #%d invalid.\n\n", faceid + 1 );
+ }
+}
+
+
+// unspecified error encountered ----------------------------------------------
+//
+void Face::Error() const
+{
+ ErrorMessage( "\n***ERROR*** in object of class BspLib::Face." );
+ HandleCriticalError();
+}
+
+
+// get index to type specified as string (this function is static!) -----------
+//
+int Face::GetTypeIndex( const char *type )
+{
+ for ( int i = 0; i < num_shading_types; i++ )
+ if ( stricmp( type, prop_strings[ i ] ) == 0 )
+ return prop_ids[ i ];
+
+ // -1 means type-string invalid, so no valid index can be returned
+ return -1;
+}
+
+
+// get index to color model specified as string (this function is static!) ----
+//
+int Face::GetColorModelIndex( const char *type )
+{
+ for ( int i = 0; i < num_color_models; i++ )
+ if ( stricmp( type, color_strings[ i ] ) == 0 )
+ return color_ids[ i ];
+
+ // -1 means type-string invalid, so no valid index can be returned
+ return -1;
+}
+
+
+// strings for specification of face shading type -----------------------------
+//
+const char *Face::prop_strings[] = {
+ "no_shad",
+ "flat_shad",
+ "gouraud_shad",
+ "afftex_shad",
+ "ipol1tex_shad",
+ "ipol2tex_shad",
+ "persptex_shad",
+ "material_shad",
+ "texmat_shad",
+};
+
+const int Face::prop_ids[] = {
+ no_shad,
+ flat_shad,
+ gouraud_shad,
+ afftex_shad,
+ ipol1tex_shad,
+ ipol2tex_shad,
+ persptex_shad,
+ material_shad,
+ texmat_shad,
+};
+
+const char *Face::color_strings[] = {
+ "no_col",
+ "indexed_col",
+ "rgb_col",
+ "material_col",
+};
+
+const int Face::color_ids[] = {
+ no_col,
+ indexed_col,
+ rgb_col,
+ material_col,
+};
+
+const char *Face::material_strings[] = {
+ "ambient_col",
+ "diffuse_col",
+ "specular_col",
+ "emissive_col",
+ "shininess",
+ "transparency",
+};
+
+
+// base size of face chunk ----------------------------------------------------
+//
+template <> const int ChunkRep<Face>::CHUNK_SIZE = 512;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Face.h b/tool_src/BspLib/Face.h
new file mode 100644
index 0000000..ceec44a
--- /dev/null
+++ b/tool_src/BspLib/Face.h
@@ -0,0 +1,223 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Face.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _FACE_H_
+#define _FACE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Chunk.h"
+#include "Material.h"
+#include "Plane.h"
+#include "SystemIO.h"
+#include "Texture.h"
+#include "TriMapping.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class describing a face (mainly in terms of its surface properties) --------
+//
+class Face : public virtual SystemIO {
+
+ void Error() const;
+
+public:
+
+ // shading types for faces
+ enum ShadingType {
+ no_shad = 0x1000, // fixed color (lighting independent ambient color)
+ flat_shad = 0x1001, // flat shading
+ gouraud_shad = 0x1002, // gouraud shading
+ afftex_shad = 0x2003, // affine texture mapping
+ ipol1tex_shad = 0x2004, // first order interpolated texture mapping (lin)
+ ipol2tex_shad = 0x2005, // second order interpolated texture mapping (quad)
+ persptex_shad = 0x2006, // perspective correct mapping without any interpolation
+ material_shad = 0x1007, // use material specification
+ texmat_shad = 0x3008, // textures modulated by material specification
+ num_shading_types = 9, // MUST SET THIS MANUALLY!!
+ base_mask = 0x00ff, // mask for basic shading type
+ color_mask = 0x1000, // mask to denote faces with attached color
+ texmap_mask = 0x2000, // mask to denote texture mapped faces
+ };
+
+ // color model identifiers
+ enum ColorModel {
+ no_col, // shading type has no associated color
+ indexed_col, // indexed color (color look up table index)
+ rgb_col, // color specified directly via separate channels
+ material_col, // use material specification
+ num_color_models
+ };
+
+public:
+ Face();
+ ~Face() { delete faceplane; delete facematerial; delete facemapping; delete texturename; }
+
+ Face( const Face& copyobj );
+ Face& operator =( const Face& copyobj );
+
+ int getId() const { return faceid; }
+ void setId( int id ) { faceid = id; }
+
+ Material getMaterial() const { if ( facematerial == NULL ) Error(); return *facematerial; }
+ Plane getPlane() const { if ( faceplane == NULL ) Error(); return *faceplane; }
+
+ Vector3 getPlaneNormal() const;
+ void setPlaneNormal( const Vector3& normal );
+
+ int getShadingType() const { return shadingtype; }
+ void setShadingType( int type );
+
+ int getColorType() const { return colortype; }
+ void getColorIndex( dword& col ) const { col = facecolor_indx; }
+ void getColorRGBA( ColorRGBA& col ) const { col = facecolor_rgba; }
+ void getColorChannels( float& r, float& g, float& b ) const;
+ const char *getTextureName() { return texturename; }
+
+ void setFaceColor( dword col );
+ void setFaceColor( ColorRGBA col );
+ void setTextureName( const char *tname );
+
+ int NormalValid() const { return faceplane ? faceplane->NormalValid() : FALSE; }
+ int PlaneValid() const { return faceplane ? faceplane->PlaneValid() : FALSE; }
+ int MaterialAttached() const { return ( facematerial != NULL ); }
+ int MappingAttached() const { return ( facemapping != NULL ); }
+ int FaceTexMapped() const { return ( ( shadingtype & texmap_mask ) != 0 ); }
+
+ void CalcPlane( const Vertex3& vertex1, const Vertex3& vertex2, const Vertex3& vertex3 );
+ void AttachNormal( const Vector3& normal );
+ void AttachPlane( Plane *plane );
+ void AttachMaterial( Material *mat );
+
+ int ConvertColorIndexToRGB( char *palette, int changemode );
+
+ Vertex2& MapXY( int indx );
+ Vertex2& MapUV( int indx );
+
+ void WriteFaceInfo( FILE *fp ) const;
+ void WriteNormalInfo( FILE *fp ) const;
+ void WriteMappingInfo( FILE *fp ) const;
+
+public:
+ static int GetTypeIndex( const char *type );
+ static int GetColorModelIndex( const char *type );
+
+public:
+ static const char* material_strings[]; // strings for material specification
+
+private:
+ static const char* prop_strings[]; // strings for shading types
+ static const int prop_ids[]; // ids corresponding to strings
+ static const char* color_strings[]; // strings for color models
+ static const int color_ids[]; // ids corresponding to strings
+
+private:
+ int faceid; // face's object-globally unique id
+ Plane* faceplane; // face's plane (normal vector and offset)
+
+ int shadingtype; // shading type, determines how face is rendered
+ int colortype; // color type, determines how color is specified
+
+ dword facecolor_indx; // face's color represented as color index
+ ColorRGBA facecolor_rgba; // face's color represented as rgba quadruplet
+ Material* facematerial; // OpenGL-style material properties
+ TriMapping* facemapping; // mapping definition for this face
+ char* texturename; // name of texture if any
+};
+
+// typedef chunk of faces -----------------------------------------------------
+typedef Chunk<Face> FaceChunk;
+
+// construct a Face -----------------------------------------------------------
+inline Face::Face()
+{
+ faceid = -1; // -1 means id invalid
+ shadingtype = -1; // -1 means type invalid
+ colortype = -1; // -1 means type invalid
+ faceplane = NULL; // face's plane not calculated
+ facematerial = NULL; // no material attached
+ facemapping = NULL; // no mapping attached
+ texturename = NULL; // no texture name
+}
+
+// get face's normal vector ---------------------------------------------------
+inline Vector3 Face::getPlaneNormal() const
+{
+ CHECK_DEREFERENCING(
+ if ( ( faceplane == NULL ) || !faceplane->NormalValid() )
+ Error();
+ );
+ return faceplane->getPlaneNormal();
+}
+
+// set face's normal vector ---------------------------------------------------
+inline void Face::setPlaneNormal( const Vector3& normal )
+{
+ CHECK_DEREFERENCING(
+ if ( ( faceplane == NULL ) || !faceplane->NormalValid() )
+ Error();
+ );
+ faceplane->setPlaneNormal( normal );
+}
+
+// set shading type -----------------------------------------------------------
+inline void Face::setShadingType( int type )
+{
+ CHECK_DEREFERENCING(
+ if ( ( type & base_mask ) >= num_shading_types )
+ Error();
+ );
+ shadingtype = type;
+}
+
+// set color specified in terms of a color index ------------------------------
+inline void Face::setFaceColor( dword col )
+{
+ facecolor_indx = col;
+ colortype = indexed_col;
+}
+
+// set color specified in terms of (r,g,b,a) ----------------------------------
+inline void Face::setFaceColor( ColorRGBA col )
+{
+ facecolor_rgba = col;
+ colortype = rgb_col;
+}
+
+// fetch rgb color channels converted to [0.0, 1.0] range ---------------------
+inline void Face::getColorChannels( float& r, float& g, float& b ) const
+{
+ r = facecolor_rgba.R / 255.0f;
+ g = facecolor_rgba.G / 255.0f;
+ b = facecolor_rgba.B / 255.0f;
+}
+
+// return mapping coordinates in (x,y)-domain ---------------------------------
+inline Vertex2& Face::MapXY( int indx )
+{
+ if ( facemapping == NULL )
+ facemapping = new TriMapping;
+ return facemapping->getMapXY( indx );
+}
+
+// return mapping coordinates in (u,v)-domain ---------------------------------
+inline Vertex2& Face::MapUV( int indx )
+{
+ if ( facemapping == NULL )
+ facemapping = new TriMapping;
+ return facemapping->getMapUV( indx );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _FACE_H_
+
diff --git a/tool_src/BspLib/IOData3D.cpp b/tool_src/BspLib/IOData3D.cpp
new file mode 100644
index 0000000..54c3663
--- /dev/null
+++ b/tool_src/BspLib/IOData3D.cpp
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: IOData3D.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "IOData3D.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// constructor for generic I/O class ------------------------------------------
+//
+IOData3D::IOData3D( BspObjectList objectlist, const String& filename, int checkflags ) :
+ m_objectlist( objectlist ),
+ m_filename( filename )
+{
+ if ( m_filename.IsNULL() && ( checkflags & CHECK_FILENAME ) ) {
+ ErrorMessage( "[IOData3D]: valid filename must be supplied." );
+ HandleCriticalError();
+ }
+}
+
+
+// signatures of recognized file formats --------------------------------------
+//
+const char IOData3D::AOD_SIGNATURE_1_1[] = "#AOD V1.1 ascii";
+const char IOData3D::BSP_SIGNATURE_1_1[] = "#BSP V1.1 ascii";
+const char IOData3D::VRML_SIGNATURE_1_0[] = "#VRML V1.0 ascii";
+const char IOData3D::_3DX_SIGNATURE_1_0[] = "3DX File 1.0";
+//ADD_FORMAT:
+
+
+// static string scratch pad --------------------------------------------------
+//
+const int IOData3D::TEXTLINE_MAX = 1023;
+char IOData3D::line[ TEXTLINE_MAX + 1 ] = "";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/IOData3D.h b/tool_src/BspLib/IOData3D.h
new file mode 100644
index 0000000..de5250d
--- /dev/null
+++ b/tool_src/BspLib/IOData3D.h
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: IOData3D.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _IODATA3D_H_
+#define _IODATA3D_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObjectList.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// base class for all input/output classes dealing with 3-D data --------------
+//
+class IOData3D : public virtual SystemIO {
+
+public:
+
+ // format identifiers
+ enum {
+ DONT_CREATE_OBJECT = 0x0000, // indicates to not create an object
+ UNKNOWN_FORMAT = 0x0001, // no valid signature detected
+ AOD_FORMAT_1_1 = 0x0002, // aod v1.1
+ VRML_FORMAT_1_0 = 0x0003, // vrml v1.0
+ BSP_FORMAT_1_1 = 0x0004, // bsp v1.1
+ _3DX_FORMAT_1_0 = 0x0005, // 3dx v1.0
+ //ADD_FORMAT:
+ };
+
+protected:
+
+ // construction flags
+ enum {
+ NO_CHECKS = 0x0000, // no validity checks whatsoever
+ CHECK_FILENAME = 0x0001, // check if supplied filename is valid pointer
+ ALL_CHECKS = 0x0001
+ };
+
+public:
+ IOData3D( BspObjectList objectlist, const String& filename, int checkflags = ALL_CHECKS );
+ ~IOData3D() { }
+
+ BspObjectList getObjectList() const { return m_objectlist; }
+ String getFileName() const { return m_filename; }
+ void setFileName( const String& filename ) { m_filename = filename; }
+
+protected:
+ BspObjectList m_objectlist; // object database
+ String m_filename; // name of data file
+
+protected:
+ // file signatures
+ static const char AOD_SIGNATURE_1_1[];
+ static const char VRML_SIGNATURE_1_0[];
+ static const char BSP_SIGNATURE_1_1[];
+ static const char _3DX_SIGNATURE_1_0[];
+ //ADD_FORMAT:
+
+ // storage for a single line of text
+ static const int TEXTLINE_MAX;
+ static char line[];
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _IODATA3D_H_
+
diff --git a/tool_src/BspLib/InputData3D.cpp b/tool_src/BspLib/InputData3D.cpp
new file mode 100644
index 0000000..48954c0
--- /dev/null
+++ b/tool_src/BspLib/InputData3D.cpp
@@ -0,0 +1,175 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: InputData3D.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "InputData3D.h"
+#include "AodInput.h"
+#include "BspInput.h"
+#include "VrmlFile.h"
+//ADD_FORMAT:
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// "virtual" constructor for different input format objects -------------------
+//
+InputData3D::InputData3D( BspObjectList objectlist, const char *filename, int format ) :
+ IOData3D( objectlist, String( filename ) ),
+ m_data( NULL )
+{
+ // create "real" input object according to format of input file
+ if ( format != DONT_CREATE_OBJECT ) {
+ switch ( m_objectformat = ReadFileSignature() ) {
+
+ case AOD_FORMAT_1_1:
+ m_data = new AodInput( objectlist, filename );
+ break;
+
+ case BSP_FORMAT_1_1:
+ m_data = new BspInput( objectlist, filename );
+ break;
+
+ case VRML_FORMAT_1_0:
+ m_data = new VrmlFile( objectlist, filename );
+ break;
+
+ case _3DX_FORMAT_1_0:
+ //m_data = new ThreeDXInput( objectlist, filename );
+ //TODO: add 3dx support
+ break;
+
+ //ADD_FORMAT:
+
+ default:
+ ErrorMessage( "[InputData3D]: Unrecognized input file format." );
+ m_objectformat = UNKNOWN_FORMAT;
+ }
+ } else {
+ m_objectformat = format;
+ }
+
+ m_inputok = m_data ? m_data->InputDataValid() : FALSE;
+}
+
+
+// virtual destructor ---------------------------------------------------------
+//
+InputData3D::~InputData3D()
+{
+ // delete "real" object
+ delete m_data;
+}
+
+
+// redirection to ParseObjectData() of "real" object --------------------------
+//
+int InputData3D::ParseObjectData()
+{
+ return m_data ? m_data->ParseObjectData() : FALSE;
+}
+
+
+// determine file type according to signature in first line -------------------
+//
+int InputData3D::ReadFileSignature()
+{
+ FileAccess sig( m_filename, "r" );
+ sig.ReadLine( line, TEXTLINE_MAX, CHECK_ERRORS );
+
+ int filetype = UNKNOWN_FORMAT;
+
+ if ( strncmp( line, AOD_SIGNATURE_1_1, strlen( AOD_SIGNATURE_1_1 ) ) == 0 )
+ filetype = AOD_FORMAT_1_1;
+ else if ( strncmp( line, BSP_SIGNATURE_1_1, strlen( BSP_SIGNATURE_1_1 ) ) == 0 )
+ filetype = BSP_FORMAT_1_1;
+ else if ( strncmp( line, VRML_SIGNATURE_1_0, strlen( VRML_SIGNATURE_1_0 ) ) == 0 )
+ filetype = VRML_FORMAT_1_0;
+ else if ( strncmp( line, _3DX_SIGNATURE_1_0, strlen( _3DX_SIGNATURE_1_0 ) ) == 0 )
+ filetype = _3DX_FORMAT_1_0;
+ //ADD_FORMAT:
+
+ return filetype;
+}
+
+
+// set flag controlling color index to RGB conversion -------------------------
+//
+int InputData3D::EnableRGBConversion( int enable )
+{
+ int precstate = getRGBConversionFlag();
+ if ( enable )
+ PostProcessingFlags |= CONVERT_COLINDXS_TO_RGB;
+ else
+ PostProcessingFlags &= ~CONVERT_COLINDXS_TO_RGB;
+ return precstate;
+}
+
+
+// set flag controlling application of object scale factors -------------------
+//
+int InputData3D::EnableScaleFactors( int enable )
+{
+ int precstate = getScaleFactorsFlag();
+ if ( enable )
+ PostProcessingFlags |= FILTER_SCALE_FACTORS;
+ else
+ PostProcessingFlags &= ~FILTER_SCALE_FACTORS;
+ return precstate;
+}
+
+
+// set flag controlling change of axes per command ----------------------------
+//
+int InputData3D::EnableAxesChange( int enable )
+{
+ int precstate = getAxesChangeFlag();
+ if ( enable )
+ PostProcessingFlags |= DO_AXES_EXCHANGE;
+ else
+ PostProcessingFlags &= ~DO_AXES_EXCHANGE;
+ return precstate;
+}
+
+
+// set flag controlling enforcement of maximum coordinate extent --------------
+//
+int InputData3D::EnableMaximumExtent( int enable, double extent )
+{
+ int precstate = getEnforceExtentsFlag();
+ MaximumExtentToForce = extent;
+ if ( enable )
+ PostProcessingFlags |= FORCE_MAXIMUM_EXTENT;
+ else
+ PostProcessingFlags &= ~FORCE_MAXIMUM_EXTENT;
+ return precstate;
+}
+
+
+// set flag controlling n-gon enabling/disabling -------------------------------
+//
+int InputData3D::EnableAllowNGons( int enable )
+{
+ int precstate = getAllowNGonFlag();
+ if ( enable )
+ PostProcessingFlags |= ALLOW_N_GONS;
+ else
+ PostProcessingFlags &= ~ALLOW_N_GONS;
+ return precstate;
+}
+
+
+// InputData3D specific static variables --------------------------------------
+//
+dword InputData3D::PostProcessingFlags = InputData3D::FILTER_SCALE_FACTORS | InputData3D::DO_AXES_EXCHANGE;
+double InputData3D::MaximumExtentToForce = 100.0;
+const char InputData3D::parser_err_str[] = "\nObject parser: **ERROR** ";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/InputData3D.h b/tool_src/BspLib/InputData3D.h
new file mode 100644
index 0000000..ab295b3
--- /dev/null
+++ b/tool_src/BspLib/InputData3D.h
@@ -0,0 +1,83 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: InputData3D.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _INPUTDATA3D_H_
+#define _INPUTDATA3D_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObjectList.h"
+#include "IOData3D.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// generic input class for 3-D data -------------------------------------------
+//
+class InputData3D : public IOData3D {
+
+public:
+ // flags for automatic postprocessing of input data
+ enum {
+ CONVERT_COLINDXS_TO_RGB = 0x0001,
+ FILTER_SCALE_FACTORS = 0x0002,
+ FILTER_AXES_DIR_SWITCH = 0x0004,
+ FILTER_AXES_EXCHANGE = 0x0008,
+ DO_AXES_EXCHANGE = FILTER_AXES_DIR_SWITCH | FILTER_AXES_EXCHANGE,
+ FORCE_MAXIMUM_EXTENT = 0x0010,
+ ALLOW_N_GONS = 0x0020,
+ };
+
+public:
+ InputData3D( BspObjectList objectlist, const char *filename, int format = UNKNOWN_FORMAT );
+ virtual ~InputData3D();
+
+ virtual int ParseObjectData(); // parse data file
+
+ int getObjectFormat() const { return m_objectformat; } // get format of "real" object
+ InputData3D* getRealObject() const { return m_data; } // get pointer to "real" object
+
+ int InputDataValid() const { return m_inputok; } // input data parsed ok?
+
+ // set/reset flags for automatic postprocessing of input data
+ static int EnableRGBConversion( int enable );
+ static int EnableScaleFactors( int enable );
+ static int EnableAxesChange( int enable );
+ static int EnableMaximumExtent( int enable, double extent );
+ static int EnableAllowNGons( int enable );
+
+ // get state of flags for automatic postprocessing of input data
+ static int getRGBConversionFlag() { return ( ( PostProcessingFlags & CONVERT_COLINDXS_TO_RGB ) == CONVERT_COLINDXS_TO_RGB ); }
+ static int getScaleFactorsFlag() { return ( ( PostProcessingFlags & FILTER_SCALE_FACTORS ) == FILTER_SCALE_FACTORS ); }
+ static int getAxesChangeFlag() { return ( ( PostProcessingFlags & DO_AXES_EXCHANGE ) == DO_AXES_EXCHANGE ); }
+ static int getEnforceExtentsFlag() { return ( ( PostProcessingFlags & FORCE_MAXIMUM_EXTENT ) == FORCE_MAXIMUM_EXTENT ); }
+ static double getMaxExtents() { return MaximumExtentToForce; }
+ static int getAllowNGonFlag() { return ( ( PostProcessingFlags & ALLOW_N_GONS ) == ALLOW_N_GONS ); }
+
+private:
+ int ReadFileSignature();
+
+protected:
+ static dword PostProcessingFlags;
+ static double MaximumExtentToForce;
+ static const char parser_err_str[];
+
+protected:
+ int m_objectformat;
+ int m_inputok;
+
+private:
+ InputData3D* m_data;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _INPUTDATA3D_H_
+
diff --git a/tool_src/BspLib/LineSeg.cpp b/tool_src/BspLib/LineSeg.cpp
new file mode 100644
index 0000000..7fc1872
--- /dev/null
+++ b/tool_src/BspLib/LineSeg.cpp
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: LineSeg.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// check if a single vertex lies on a line segment ----------------------------
+//
+int LineSeg2::PointOnLineSeg( const Vertex2& vertex ) const
+{
+ if ( m_dirvec.IsNullVector() )
+ return FALSE;
+
+ Vector2 vertexvec( vertex - m_basevtx );
+ Vector2 crossprod( vertexvec, m_dirvec );
+
+ if ( ( crossprod.VecLength() / m_dirvec.VecLength() ) > EPS_POINT_ON_LINE )
+ return FALSE;
+
+ double t;
+ if ( fabs( m_dirvec.X ) >= EPS_DENOM_ZERO )
+ t = vertexvec.X / m_dirvec.X;
+ else if ( fabs( m_dirvec.Y ) >= EPS_DENOM_ZERO )
+ t = vertexvec.Y / m_dirvec.Y;
+ else
+ return FALSE;
+
+ return ( ( t >= EPS_POINT_ON_LINESEG ) && ( t <= 1.0 - EPS_POINT_ON_LINESEG ) );
+}
+
+
+// check if a single vertex lies on a line segment ----------------------------
+//
+int LineSeg3::PointOnLineSeg( const Vertex3& vertex ) const
+{
+ if ( m_dirvec.IsNullVector() )
+ return FALSE;
+
+ Vector3 vertexvec( vertex - m_basevtx );
+ Vector3 crossprod( vertexvec, m_dirvec );
+
+ // check if point lies on line
+ if ( ( crossprod.VecLength() / m_dirvec.VecLength() ) > EPS_POINT_ON_LINE )
+ return FALSE;
+
+ // check if it lies between start- and endvertex of lineseg
+ double t;
+ if ( fabs( m_dirvec.X ) >= EPS_DENOM_ZERO )
+ t = vertexvec.X / m_dirvec.X;
+ else if ( fabs( m_dirvec.Y ) >= EPS_DENOM_ZERO )
+ t = vertexvec.Y / m_dirvec.Y;
+ else if ( fabs( m_dirvec.Z ) >= EPS_DENOM_ZERO )
+ t = vertexvec.Z / m_dirvec.Z;
+ else
+ return FALSE;
+
+ return ( ( t >= EPS_POINT_ON_LINESEG ) && ( t <= 1.0 - EPS_POINT_ON_LINESEG ) );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/LineSeg2.h b/tool_src/BspLib/LineSeg2.h
new file mode 100644
index 0000000..96cdbb8
--- /dev/null
+++ b/tool_src/BspLib/LineSeg2.h
@@ -0,0 +1,46 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: LineSeg2.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _LINESEG2_H_
+#define _LINESEG2_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vector2.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// line segment in 2-space ----------------------------------------------------
+//
+class LineSeg2 {
+
+public:
+ LineSeg2( const Vertex2& basevtx, const Vector2& dirvec );
+ ~LineSeg2() { }
+
+ int PointOnLineSeg( const Vertex2& vertex ) const;
+
+private:
+ Vertex2 m_basevtx;
+ Vector2 m_dirvec;
+};
+
+// construct a LineSeg2 using a basevertex and a direction vector -------------
+inline LineSeg2::LineSeg2( const Vertex2& basevtx, const Vector2& dirvec )
+{
+ m_basevtx = basevtx;
+ m_dirvec = dirvec;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _LINESEG2_H_
+
diff --git a/tool_src/BspLib/LineSeg3.h b/tool_src/BspLib/LineSeg3.h
new file mode 100644
index 0000000..0f436f3
--- /dev/null
+++ b/tool_src/BspLib/LineSeg3.h
@@ -0,0 +1,46 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: LineSeg3.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _LINESEG3_H_
+#define _LINESEG3_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vector3.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// line segment in 3-space ----------------------------------------------------
+//
+class LineSeg3 {
+
+public:
+ LineSeg3( const Vertex3& basevtx, const Vector3& dirvec );
+ ~LineSeg3() { }
+
+ int PointOnLineSeg( const Vertex3& vertex ) const;
+
+private:
+ Vertex3 m_basevtx;
+ Vector3 m_dirvec;
+};
+
+// construct a LineSeg3 using a basevertex and a direction vector -------------
+inline LineSeg3::LineSeg3( const Vertex3& basevtx, const Vector3& dirvec )
+{
+ m_basevtx = basevtx;
+ m_dirvec = dirvec;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _LINESEG3_H_
+
diff --git a/tool_src/BspLib/Makefile b/tool_src/BspLib/Makefile
new file mode 100644
index 0000000..7385303
--- /dev/null
+++ b/tool_src/BspLib/Makefile
@@ -0,0 +1,62 @@
+# BspLib makefile
+
+CFILES = AodFormat.cpp\
+AodInput.cpp\
+AodOutput.cpp\
+BRep.cpp\
+BSPNode.cpp\
+BSPTree.cpp\
+BoundingBox.cpp\
+BspFormat.cpp\
+BspInput.cpp\
+BspObject.cpp\
+BspObjectList.cpp\
+BspOutput.cpp\
+BspTool.cpp\
+EpsAreas.cpp\
+Face.cpp\
+IOData3D.cpp\
+InputData3D.cpp\
+LineSeg.cpp\
+Mapping.cpp\
+ObjectAodFormat.cpp\
+ObjectBSPNode.cpp\
+ObjectBinFormat.cpp\
+ObjectBspFormat.cpp\
+OutputData3D.cpp\
+Polygon.cpp\
+PolygonList.cpp\
+SingleFormat.cpp\
+SingleInput.cpp\
+SingleOutput.cpp\
+SystemIO.cpp\
+Texture.cpp\
+Transform2.cpp\
+Transform3.cpp\
+TriMapping.cpp\
+Vertex.cpp\
+VertexChunk.cpp\
+VrmlFile.cpp
+
+
+CFLAGS = -g -O2 -I../QvLib -I. -fno-for-scope\
+ -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp
+
+# use this for JPEG support
+#CFLAGS = -g -O2 -I../QvLib -I. -fno-for-scope\
+# -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DUSE_JPEG_LIBRARY
+
+all: libbsp.a
+
+libbsp.a: $(CFILES:.cpp=.o)
+ ar rc libbsp.a $(CFILES:.cpp=.o)
+ ranlib libbsp.a
+
+.cpp.o:
+ gcc $(CFLAGS) -o $@ -c $<
+
+clean:
+ rm -f *.o *.a *~
+
+
+
diff --git a/tool_src/BspLib/Mapping.cpp b/tool_src/BspLib/Mapping.cpp
new file mode 100644
index 0000000..956d66c
--- /dev/null
+++ b/tool_src/BspLib/Mapping.cpp
@@ -0,0 +1,63 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Mapping.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Mapping.h"
+#include "Chunk.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// write mapping info in vertexindexes with mappings format -------------------
+//
+void Mapping::WriteMappingInfo( FILE *fp ) const
+{
+ // write list of vertex indexes
+ int i = 0;
+ for ( i = 0; i < numvertexindxs; i++ ) {
+ fprintf( fp, ( i == numvertexindxs - 1 ) ?
+ "%d\n" : "%d, ", facevertexindxs[ i ] + 1 );
+ }
+
+ // write (u,v) coordinates
+ for ( i = 0; i < numvertexindxs; i++ ) {
+ fprintf( fp, "%f, \t%f\n",
+ mappingcoordinates[ i ].getX(),
+ mappingcoordinates[ i ].getY() );
+ }
+
+ fprintf( fp, "\n" );
+}
+
+
+// error in search of vertices ------------------------------------------------
+//
+void Mapping::Error( int vertindx )
+{
+ char *line = new char[ 1024 ];
+// fprintf( stderr, "***ERROR*** Correspondence not found (%d)!\n", corrno + 1 );
+ sprintf( line, "***ERROR*** Correspondence not found!\nsought vertex %d", vertindx + 1 );
+ ErrorMessage( line );
+ delete line;
+/*
+ fprintf( stderr, "list of vertices:\n" );
+ for ( int i = 0; i < numvertexindxs; i++ )
+ fprintf( stderr, "vertex %d\n", facevertexindxs[ i ] + 1 );
+*/
+ HandleCriticalError();
+}
+
+
+// size of mapping chunk ------------------------------------------------------
+//
+template <> const int ChunkRep<Mapping>::CHUNK_SIZE = 256;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Mapping.h b/tool_src/BspLib/Mapping.h
new file mode 100644
index 0000000..52d01d0
--- /dev/null
+++ b/tool_src/BspLib/Mapping.h
@@ -0,0 +1,89 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Mapping.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _MAPPING_H_
+#define _MAPPING_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Chunk.h"
+#include "SystemIO.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+#define V_FACEVTXMAX 32 // vertices per face (actually, per polygon)
+
+
+// class that describes mapping for face with many vertices -------------------
+//
+class Mapping : public virtual SystemIO {
+
+ void Error( int vertindx );
+
+public:
+ Mapping() { numvertexindxs = 0; }
+ ~Mapping() { }
+
+ void InsertFaceVertex( int vindx ) { facevertexindxs[ numvertexindxs++ ] = vindx; }
+ void SetCorrespondence( int vindx, Vertex2 vertex );
+ Vertex2 FetchMapPoint( int vertindx );
+
+ int getNumVertices() { return numvertexindxs; }
+ void setNumVertices( int num ) { numvertexindxs = num; }
+ void setMappingCoordinates( int k, const Vertex2& vertex);
+
+ void WriteMappingInfo( FILE *fp ) const;
+
+private:
+ int numvertexindxs;
+ int facevertexindxs[ V_FACEVTXMAX ];
+ Vertex2 mappingcoordinates[ V_FACEVTXMAX ];
+};
+
+// typedef chunk of mappings --------------------------------------------------
+typedef Chunk<Mapping> MappingChunk;
+
+// set mapping coordinates ----------------------------------------------------
+inline void Mapping::setMappingCoordinates( int k, const Vertex2& vertex)
+{
+ if ( k < V_FACEVTXMAX )
+ mappingcoordinates[ k ] = vertex;
+ else
+ Error( k );
+}
+
+// set single correspondence -------------------------------------------------
+inline void Mapping::SetCorrespondence( int vindx, Vertex2 vertex )
+{
+ if ( numvertexindxs < V_FACEVTXMAX ) {
+ facevertexindxs[ numvertexindxs ] = vindx;
+ mappingcoordinates[ numvertexindxs ] = vertex;
+ numvertexindxs++;
+ } else {
+ Error( numvertexindxs );
+ }
+}
+
+// fetch corresponding mapping to face vertex ---------------------------------
+inline Vertex2 Mapping::FetchMapPoint( int vertindx )
+{
+ for ( int i = 0; i < numvertexindxs; i++ )
+ if ( facevertexindxs[ i ] == vertindx )
+ return mappingcoordinates[ i ];
+ Error( vertindx );
+ return Vertex2( 0, 0 ); // never reached
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _MAPPING_H_
+
diff --git a/tool_src/BspLib/Material.h b/tool_src/BspLib/Material.h
new file mode 100644
index 0000000..a0c0f1f
--- /dev/null
+++ b/tool_src/BspLib/Material.h
@@ -0,0 +1,57 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Material.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _MATERIAL_H_
+#define _MATERIAL_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class that describes OpenGL-style material properties ----------------------
+//
+class Material {
+
+public:
+ Material() { }
+ ~Material() { }
+
+ ColorRGBA getAmbientColor() { return ambientcolor; }
+ ColorRGBA getDiffuseColor() { return diffusecolor; }
+ ColorRGBA getSpecularColor() { return specularcolor; }
+ ColorRGBA getEmissiveColor() { return emissivecolor; }
+
+ void setAmbientColor( ColorRGBA col ) { ambientcolor = col; ambientcolor.A = 255; }
+ void setDiffuseColor( ColorRGBA col ) { diffusecolor = col; diffusecolor.A = 255; }
+ void setSpecularColor( ColorRGBA col ) { specularcolor = col; specularcolor.A = 255; }
+ void setEmissiveColor( ColorRGBA col ) { emissivecolor = col; emissivecolor.A = 255; }
+
+ float getShininess() { return shininess; }
+ float getTransparency() { return transparency; }
+
+ void setShininess( float s ) { shininess = s; }
+ void setTransparency( float t ) { transparency = t; }
+
+private:
+ ColorRGBA ambientcolor; // OpenGL-style material properties
+ ColorRGBA diffusecolor;
+ ColorRGBA specularcolor;
+ ColorRGBA emissivecolor;
+ float shininess;
+ float transparency;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _MATERIAL_H_
+
diff --git a/tool_src/BspLib/ObjectAodFormat.cpp b/tool_src/BspLib/ObjectAodFormat.cpp
new file mode 100644
index 0000000..be09e64
--- /dev/null
+++ b/tool_src/BspLib/ObjectAodFormat.cpp
@@ -0,0 +1,200 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: ObjectAodFormat.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "ObjectAodFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// write list of vertices -----------------------------------------------------
+//
+int ObjectAodFormat::WriteVertexList( FileAccess& output )
+{
+ if ( numvertices > 0 ) {
+
+ output.WriteLine( "; list of all vertices comprising the object -----------------------------\n" );
+ output.WriteLine( "; numbering starts with 1\n" );
+
+ sprintf( line, "%s\n", _vertices_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numvertices; i++ ) {
+ sprintf( line, "%f,\t%f,\t%f\t; %d\n",
+ vertexlist[ i ].getX(),
+ vertexlist[ i ].getY(),
+ vertexlist[ i ].getZ(),
+ i + 1 );
+ output.WriteLine( line );
+ }
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write list of faces --------------------------------------------------------
+//
+int ObjectAodFormat::WriteFaceList( FileAccess& output )
+{
+ if ( numpolygons > 0 ) {
+
+ output.WriteLine( "; list of all faces ------------------------------------------------------\n" );
+ output.WriteLine( "; numbering starts with 1\n" );
+
+ sprintf( line, "%s\n", _faces_str );
+ output.WriteLine( line );
+
+ int i = 0;
+ WriteFaceInfo( output, polygonlist.FetchHead(), i );
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write info about single face (vertexindexes comprising the face) -----------
+//
+void ObjectAodFormat::WriteFaceInfo( FileAccess& output, Polygon *poly, int& num )
+{
+#if 0
+ if ( poly->getNext() )
+ WriteFaceInfo( output, poly->getNext(), num );
+
+ poly->WriteVertexList( output, FALSE );
+ sprintf( line, "\t\t; %d\n", ++num );
+ output.WriteLine( line );
+
+#else
+ // scan polygons according to face id
+ Polygon *scan = NULL;
+ for ( int facecount = 0; ; facecount++ ) {
+ for ( scan = poly; scan; scan = scan->getNext() ) {
+ if ( scan->getFaceId() == facecount )
+ break;
+ }
+ if ( scan == NULL )
+ break;
+ scan->WriteVertexList( output, FALSE );
+ sprintf( line, "\t\t; %d\n", ++num );
+ output.WriteLine( line );
+ }
+
+ //NOTE:
+ // if there is no exact 1:1 correspondence between
+ // polygons and faces this will not work correctly!
+ // since for each face only one polygon is written,
+ // tessellated vrml cones and cylinders cannot be
+ // correctly written to AOD files.
+
+#endif
+}
+
+
+// write surface properties of faces ------------------------------------------
+//
+int ObjectAodFormat::WriteFaceProperties( FileAccess& output )
+{
+ if ( numfaces > 0 ) {
+
+ output.WriteLine( "; face material properties (color, texture, etc.) ------------------------\n" );
+
+ sprintf( line, "%s\n", _faceproperties_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numfaces; i++ )
+ facelist[ i ].WriteFaceInfo( output );
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write face normals ---------------------------------------------------------
+//
+int ObjectAodFormat::WriteNormals( FileAccess& output )
+{
+ if ( numnormals > 0 ) {
+
+ output.WriteLine( "; face normals -----------------------------------------------------------\n" );
+
+ sprintf( line, "%s\n", _facenormals_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numfaces /*numnormals*/; i++ )
+ facelist[ i ].WriteNormalInfo( output );
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write list of textures -----------------------------------------------------
+//
+int ObjectAodFormat::WriteTextureList( FileAccess& output )
+{
+ if ( numtextures > 0 ) {
+
+ output.WriteLine( "; texture definitions (sizes and filenames) ------------------------------\n" );
+
+ sprintf( line, "%s\n", _textures_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numtextures; i++ )
+ texturelist[ i ].WriteInfo( output );
+ }
+
+ return output.Status();
+}
+
+
+// write list of mapping coordinates (correspondences) ------------------------
+//
+int ObjectAodFormat::WriteMappingList( FileAccess& output )
+{
+ if ( numtexmappedfaces > 0 ) {
+
+ output.WriteLine( "; mapping parameters for textured faces ----------------------------------\n" );
+ sprintf( line, "%s\n", _correspondences_str );
+ output.WriteLine( line );
+ output.WriteLine( "\n" );
+
+ int curfaceno = 0;
+ for ( int i = 0; i < numtexmappedfaces; i++, curfaceno++ ) {
+ while ( !facelist[ curfaceno ].FaceTexMapped() )
+ curfaceno++;
+ sprintf( line, "; correspondence %d (face %d)\n", i + 1, curfaceno + 1 );
+ output.WriteLine( line );
+
+ if ( mappinglist.getNumElements() > i )
+ mappinglist[ i ].WriteMappingInfo( output );
+ else
+ facelist[ curfaceno ].WriteMappingInfo( output );
+ }
+ }
+
+ return output.Status();
+}
+
+
+// string scratchpad ----------------------------------------------------------
+//
+char ObjectAodFormat::line[ 1024 ] = "";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/ObjectAodFormat.h b/tool_src/BspLib/ObjectAodFormat.h
new file mode 100644
index 0000000..e900616
--- /dev/null
+++ b/tool_src/BspLib/ObjectAodFormat.h
@@ -0,0 +1,52 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: ObjectAodFormat.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _OBJECTAODFORMAT_H_
+#define _OBJECTAODFORMAT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "AodFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// BspObject capable of AodFormat I/O operations ------------------------------
+//
+class ObjectAodFormat : public BspObject, public AodFormat {
+
+public:
+ ObjectAodFormat( BspObject& object, AodFormat& format );
+ ~ObjectAodFormat() { }
+
+ virtual int WriteVertexList( FileAccess& output );
+ virtual int WriteFaceList( FileAccess& output );
+ virtual void WriteFaceInfo( FileAccess& output, Polygon *poly, int& num );
+ virtual int WriteFaceProperties( FileAccess& output );
+ virtual int WriteTextureList( FileAccess& output );
+ virtual int WriteMappingList( FileAccess& output );
+ virtual int WriteNormals( FileAccess& output );
+
+private:
+ static char line[]; // scratchpad
+};
+
+// construct by copying base class objects ------------------------------------
+inline ObjectAodFormat::ObjectAodFormat( BspObject& object, AodFormat& format ) :
+ BspObject( object ),
+ AodFormat( format )
+{
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _OBJECTAODFORMAT_H_
+
diff --git a/tool_src/BspLib/ObjectBSPNode.cpp b/tool_src/BspLib/ObjectBSPNode.cpp
new file mode 100644
index 0000000..53e08a1
--- /dev/null
+++ b/tool_src/BspLib/ObjectBSPNode.cpp
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: ObjectBSPNode.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "ObjectBSPNode.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// create linear object list from objects attached to nodes -------------------
+//
+BspObject *ObjectBSPNode::CreateObjectList()
+{
+ // process tree from its leaves upwards
+ BspObject *front = frontsubtree ? frontsubtree->CreateObjectList() : NULL;
+ BspObject *back = backsubtree ? backsubtree->CreateObjectList() : NULL;
+ BspObject *scan = NULL;
+ if ( front != NULL ) {
+ // append back-list to front-list if front-list exists
+
+ for ( scan = front; scan->next; scan = scan->next ) ;
+ scan->next = back;
+ }
+
+ if ( boundingbox != NULL ) {
+ static BspObject *headobject;
+ if ( ( headobject = boundingbox->containedobject ) != NULL ) {
+ // scan list and merge all subsequent objects into head object
+ static BspObject *scan;
+ for ( scan = headobject->next; scan; scan = scan->next ) {
+ headobject->MergeObjects( scan );
+ // invalidate other object's polygonlist
+ scan->getPolygonList().InvalidateList();
+ }
+ // delete all objects that have been merged into head
+ delete headobject->next;
+ // single object, no list
+ headobject->next = NULL;
+ // return head object now encompassing entire list
+ return headobject;
+ } else {
+ // return contatenated list for internal nodes with bounding box
+ return front ? front : back;
+ }
+ } else {
+ // simply return contatenated list for nodes without bounding box
+ return front ? front : back;
+ }
+}
+
+
+// merge all objects contained in tree into passed object ---------------------
+//
+void ObjectBSPNode::MergeTreeNodeObjects( BspObject *newobject )
+{
+ if ( separatorplane == NULL ) {
+ // merge leaf into already existing cumulative object
+ newobject->MergeObjects( boundingbox->containedobject );
+ // unlink list from already merged object
+ boundingbox->containedobject->next = NULL;
+
+ //NOTE:
+ // the merged objects must not be freed at this point,
+ // since they are still needed for the subsequent merging
+ // of bsp trees! nevertheless, their next field must be
+ // set to null, to prevent crosslinking of leaves.
+
+ } else {
+ // process subtrees; order not relevant in any way
+ if ( frontsubtree ) frontsubtree->MergeTreeNodeObjects( newobject );
+ if ( backsubtree ) backsubtree->MergeTreeNodeObjects( newobject );
+ }
+}
+
+
+// create unified (separator plane/polygon bsp) from object bsp tree ----------
+//
+BSPNode *ObjectBSPNode::CreateUnifiedBSPTree()
+{
+ //NOTE:
+ // the BSPTrees of the BspObjects are invalidated after they
+ // have been integrated into the unified BSPTree. this is done
+ // to prevent accidental deletion at the time when the underlying
+ // objects will be deleted. (which will normally be done in
+ // DeleteNodeBspObjects() later on.)
+
+ if ( separatorplane == NULL ) {
+ // node is leaf: return object's bsp tree
+ static BSPNode *root;
+ root = boundingbox->containedobject->getBSPTree().getRoot();
+ boundingbox->containedobject->getBSPTree().InvalidateTree();
+ return root;
+ } else {
+ // node is separator (internal node): create separator bsp node
+ BSPNode *front = frontsubtree ? frontsubtree->CreateUnifiedBSPTree() : NULL;
+ BSPNode *back = backsubtree ? backsubtree->CreateUnifiedBSPTree() : NULL;
+ return new BSPNode( front, back, NULL, NULL, separatorplane, NULL );
+ }
+}
+
+
+// merge all objects contained in object bsp tree into single object and tree -
+//
+BspObject *ObjectBSPNode::CreateMergedBSPTree()
+{
+ //NOTE:
+ // this function may only be invoked on ObjectBSPNodes which
+ // actually contain objects with valid BSPTrees! so, it may only
+ // be invoked after successful bsp compilation.
+
+ // create new object to encompass all other objects
+ BspObject *newobject = new BspObject;
+
+ // merge objects of nodes into one big object
+ MergeTreeNodeObjects( newobject );
+
+ // create unified bsp tree for all contained objects and their respective separators
+ newobject->getBSPTree().InitTree( CreateUnifiedBSPTree() );
+ newobject->numbsppolygons = 0;
+ newobject->getBSPTree()->NumberBSPNodes( newobject->numbsppolygons ); //CAVEAT: sind nicht alles Polygone!!! //TODO
+
+ newobject->UpdateAttributeNumbers();
+ return newobject;
+}
+
+
+// delete all BSPObjects attached to bounding boxes contained in tree ---------
+//
+void ObjectBSPNode::DeleteNodeBspObjects()
+{
+ if ( separatorplane == NULL ) {
+ // delete leaf
+ delete boundingbox->containedobject;
+ boundingbox->containedobject = NULL;
+ } else {
+ // detach separator plane from node to prevent accidental
+ // deletion later on. (planes are still used by unified
+ // bsp tree.)
+ separatorplane = NULL;
+ // process subtrees; order not relevant in any way
+ if ( frontsubtree ) frontsubtree->DeleteNodeBspObjects();
+ if ( backsubtree ) backsubtree->DeleteNodeBspObjects();
+ }
+}
+
+
+// traverse bsp tree (preorder) and number nodes as encountered ---------------
+//
+void ObjectBSPNode::NumberBSPNodes( int& curno )
+{
+ // never used
+}
+
+
+// write bsp tree structure to output file (preorder traversal) ---------------
+//
+void ObjectBSPNode::WriteBSPTree( FILE *fp ) const
+{
+ // never used
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/ObjectBSPNode.h b/tool_src/BspLib/ObjectBSPNode.h
new file mode 100644
index 0000000..e5301fe
--- /dev/null
+++ b/tool_src/BspLib/ObjectBSPNode.h
@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: ObjectBSPNode.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _OBJECTBSPNODE_H_
+#define _OBJECTBSPNODE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BoundingBox.h"
+#include "BspObject.h"
+#include "Plane.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// node of object bsp tree (a bsp tree of whole objects instead of polygons) --
+//
+class ObjectBSPNode {
+
+public:
+ ObjectBSPNode( ObjectBSPNode *front = NULL, ObjectBSPNode *back = NULL, Plane *sep = NULL, BoundingBox *bbox = NULL, int id = -1 );
+ ~ObjectBSPNode() { delete separatorplane; delete boundingbox; delete frontsubtree; delete backsubtree; }
+
+ void NumberBSPNodes( int& curno );
+ void WriteBSPTree( FILE *fp ) const;
+
+ BspObject* CreateObjectList();
+ BspObject* CreateMergedBSPTree();
+
+ void DeleteNodeBspObjects();
+
+ int getNodeNumber() const { return nodenumber; }
+ Plane* getSeparatorPlane() const { return separatorplane; }
+ BoundingBox* getBoundingBox() const { return boundingbox; }
+ ObjectBSPNode* getFrontSubtree() const { return frontsubtree; }
+ ObjectBSPNode* getBackSubtree() const { return backsubtree; }
+
+private:
+ void MergeTreeNodeObjects( BspObject *newobject );
+ BSPNode* CreateUnifiedBSPTree();
+
+private:
+ int nodenumber; // this node's id
+ Plane* separatorplane; // plane inducing two halfspaces; NULL for leaves
+ BoundingBox* boundingbox; // attached bounding box; NULL for internal nodes
+ ObjectBSPNode* frontsubtree; // tree in front halfspace
+ ObjectBSPNode* backsubtree; // tree in back halfspace
+};
+
+// construct node -------------------------------------------------------------
+inline ObjectBSPNode::ObjectBSPNode( ObjectBSPNode *front, ObjectBSPNode *back, Plane *sep, BoundingBox *bbox, int id )
+{
+ frontsubtree = front;
+ backsubtree = back;
+ separatorplane = sep;
+ boundingbox = bbox;
+ nodenumber = id;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _OBJECTBSPNODE_H_
+
diff --git a/tool_src/BspLib/ObjectBSPTree.h b/tool_src/BspLib/ObjectBSPTree.h
new file mode 100644
index 0000000..5d505bc
--- /dev/null
+++ b/tool_src/BspLib/ObjectBSPTree.h
@@ -0,0 +1,97 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: ObjectBSPTree.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _OBJECTBSPTREE_H_
+#define _OBJECTBSPTREE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "ObjectBSPNode.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// bsp tree of objects; basically pointer to root node (representation class) -
+//
+class ObjectBSPTreeRep {
+
+ friend class ObjectBSPTree;
+
+private:
+ ObjectBSPTreeRep() : ref_count( 0 ) { root = NULL; }
+ ~ObjectBSPTreeRep() { delete root; }
+
+ void KillTree() { delete root; root = NULL; }
+ ObjectBSPNode* InitTree( ObjectBSPNode *rootnode );
+ ObjectBSPNode* getRoot() { return root; }
+
+ int TreeEmpty() const { return ( root == NULL ); }
+
+private:
+ int ref_count;
+ ObjectBSPNode* root;
+};
+
+// init with entire tree of ObjectBSPNode objects -----------------------------
+inline ObjectBSPNode *ObjectBSPTreeRep::InitTree( ObjectBSPNode *rootnode )
+{
+ delete root;
+ return ( root = rootnode );
+}
+
+
+// bsp tree of objects; basically pointer to root node (handle class) ---------
+//
+class ObjectBSPTree {
+
+public:
+ ObjectBSPTree() { rep = new ObjectBSPTreeRep; rep->ref_count = 1; }
+ ~ObjectBSPTree() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ ObjectBSPTree( const ObjectBSPTree& copyobj );
+ ObjectBSPTree& operator =( const ObjectBSPTree& copyobj );
+
+ // pass most operations through to ObjectBSPNode
+ ObjectBSPNode* operator->() { return rep->getRoot(); }
+
+ void KillTree() { rep->KillTree(); }
+ ObjectBSPNode* InitTree( ObjectBSPNode *rootnode ) { return rep->InitTree( rootnode ); }
+ ObjectBSPNode* getRoot() { return rep->getRoot(); }
+
+ int TreeEmpty() const { return rep->TreeEmpty(); }
+
+private:
+ ObjectBSPTreeRep* rep;
+};
+
+// copy constructor -----------------------------------------------------------
+inline ObjectBSPTree::ObjectBSPTree( const ObjectBSPTree& copyobj )
+{
+ rep = copyobj.rep;
+ rep->ref_count++;
+}
+
+// assignment operator --------------------------------------------------------
+inline ObjectBSPTree& ObjectBSPTree::operator =( const ObjectBSPTree& copyobj )
+{
+ if ( &copyobj != this ) {
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep;
+ rep->ref_count++;
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _OBJECTBSPTREE_H_
+
diff --git a/tool_src/BspLib/ObjectBinFormat.cpp b/tool_src/BspLib/ObjectBinFormat.cpp
new file mode 100644
index 0000000..c0b44a0
--- /dev/null
+++ b/tool_src/BspLib/ObjectBinFormat.cpp
@@ -0,0 +1,758 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: ObjectBinFormat.cpp
+//
+// Copyright (c) 1998-1999 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "ObjectBinFormat.h"
+#include "Transform2.h"
+
+// parsec header files
+#include "../../src/libparsec/include/od_geomv.h"
+#include "../../src/libparsec/include/od_odt.h"
+
+
+#define VERTEX_SCALE_FAC ( 1.0 / 20.0 )
+
+// default to defining.
+#ifndef BIG_ENDIAN
+//#define BIG_ENDIAN
+#endif
+
+#ifdef BIG_ENDIAN
+
+#define SWAP_16(s) ( ((word)(s) >> 8) | ((word)(s) << 8) )
+#define SWAP_32(l) ( ( ((dword)(l) ) << 24 ) | \
+ ( ((dword)(l) ) >> 24 ) | \
+ ( ((dword)(l) & 0x0000ff00) << 8 ) | \
+ ( ((dword)(l) & 0x00ff0000) >> 8 ) )
+
+#else
+
+#define SWAP_16(s) ( s )
+#define SWAP_32(l) ( l )
+
+#endif // BIG_ENDIAN
+
+
+void OD2_Geomv_out( float *value )
+{
+
+ dword tmp = SWAP_32( DW32( *value ) );
+ *(dword *)value = tmp;
+
+}
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// calculate affine mapping using face's mapping specification ----------------
+//
+void ObjectBinFormat::ODT_CalcAffineMapping( Face& face, dword *dmatrx )
+{
+ Vertex2 vtx;
+ double mat[3][3];
+ int i = 0;
+ // build xyw-matrix
+ for ( i = 0; i < 3; i++ ) {
+ vtx = face.MapXY( i );
+ mat[ 0 ][ i ] = vtx.getX() * VERTEX_SCALE_FAC;
+ mat[ 1 ][ i ] = vtx.getY() * -VERTEX_SCALE_FAC;
+ mat[ 2 ][ i ] = vtx.getW() * -VERTEX_SCALE_FAC;
+ }
+ Transform2 xyw( (const double(*)[3]) mat );
+
+ // build uv1-matrix
+ for ( i = 0; i < 3; i++ ) {
+ vtx = face.MapUV( i );
+ mat[ 0 ][ i ] = vtx.getX();
+ mat[ 1 ][ i ] = vtx.getY();
+ mat[ 2 ][ i ] = vtx.getW();
+ }
+ Transform2 uv1( (const double(*)[3]) mat );
+
+ // invert uv1
+ Transform2 uv1i;
+ if ( !uv1.Inverse( uv1i ) ) {
+ ErrorMessage( "ObjectBinFormat::ODT_CalcAffineMapping(): Collinear mapping coordinates encountered!" );
+ }
+
+ // calculate affine mapping
+ Transform2 map( xyw );
+ map.Concat( uv1i );
+
+ // store result into destination structure (9 coefficients)
+ double (*affinemap)[ 3 ] = ( double (*)[3] ) map.LinMatrixAccess();
+ fixed_t (*dest)[ 4 ] = (fixed_t (*)[4]) dmatrx;
+ for ( i = 0; i < 3; i++ ) {
+ dest[ i ][ 0 ] = FLOAT_TO_FIXED( affinemap[ i ][ 0 ] );
+ dest[ i ][ 1 ] = FLOAT_TO_FIXED( affinemap[ i ][ 1 ] );
+ dest[ i ][ 2 ] = FLOAT_TO_FIXED( 0.0 ); // third column is zero
+ dest[ i ][ 3 ] = FLOAT_TO_FIXED( affinemap[ i ][ 2 ] );
+ }
+}
+
+
+// create object recognizeable by engine (ODT format) -------------------------
+//
+byte *ObjectBinFormat::ODT_CreateEngineObject( int& memblocksize )
+{
+ // fetch object data lists
+ VertexChunk& vtxlist = getVertexList();
+ PolygonList& polylist = getPolygonList();
+ FaceChunk& facelist = getFaceList();
+ TextureChunk& texlist = getTextureList();
+
+ // calculate some basic numbers
+ int numvertices = getNumVertices();
+ int numnormals = getNumNormals();
+ int numallvtxs = numvertices + numnormals;
+ int numpolygons = BSPTreeAvailable() ? getBspPolygons() : getNumPolygons();
+ int numfaces = getNumFaces();
+ int numbspnodes = getBspPolygons();
+
+ // count number of vertices of all polygons
+ int numvertexindices = 0;
+ if ( BSPTreeAvailable() )
+ bsptree->SumVertexNums( numvertexindices );
+ else
+ numvertexindices = polylist.FetchHead()->SumVertexNumsEntireList();
+
+ // calculate size of entire object structure
+ size_t objectmemsize = sizeof( ODT_GenObject ) + // generic object header
+ sizeof( ODT_Vertex3 ) * numallvtxs + // object space vertices
+ sizeof( ODT_Vertex3 ) * numallvtxs + // view space vertices
+ sizeof( ODT_ProjPoint ) * numallvtxs + // projected vertices
+ sizeof( ODT_SPoint ) * numallvtxs + // screen space vertices
+ sizeof( ODT_Poly ) * numpolygons + // polygon control data
+ sizeof( dword ) * numvertexindices + // polygon vertindx lists
+ sizeof( ODT_Face ) * numfaces + // face control data
+ sizeof( ODT_VisPolys ) + sizeof( dword ) * numpolygons + // vispolylist
+ sizeof( ODT_BSPNode ) * ( numbspnodes + 1 ); // bsp tree
+
+ // allocate memory for all object data (only excluding texturemaps)
+ ODT_GenObject *binobj = (ODT_GenObject *) new char[ objectmemsize ];
+ memset( binobj, 0x00, objectmemsize );
+
+ // fill in objectheader
+ binobj->NextObj = NULL;
+ binobj->PrevObj = NULL;
+ binobj->NextVisObj = NULL;
+ binobj->InstanceSize = sizeof( ODT_GenObject );
+ binobj->NumVerts = numallvtxs;
+ binobj->NumPolyVerts = numvertices;
+ binobj->NumNormals = numnormals;
+ binobj->VertexList = (ODT_Vertex3 *) ( binobj + 1 );
+ binobj->X_VertexList = (ODT_Vertex3 *)
+ ( (char *) binobj->VertexList + sizeof( ODT_Vertex3 ) * numallvtxs );
+ binobj->P_VertexList = (ODT_ProjPoint *)
+ ( (char *) binobj->X_VertexList + sizeof( ODT_Vertex3 ) * numallvtxs );
+ binobj->S_VertexList = (ODT_SPoint *)
+ ( (char *) binobj->P_VertexList + sizeof( ODT_ProjPoint ) * numallvtxs );
+ binobj->NumPolys = numpolygons;
+ binobj->PolyList = (ODT_Poly *)
+ ( (char *) binobj->S_VertexList + sizeof( ODT_SPoint ) * numallvtxs );
+ binobj->NumFaces = numfaces;
+ binobj->FaceList = (ODT_Face *)
+ ( (char *) binobj->PolyList + sizeof( ODT_Poly ) * numpolygons + sizeof( dword ) * numvertexindices );
+ binobj->VisPolyList = (ODT_VisPolys *)
+ ( (char *) binobj->FaceList + sizeof( ODT_Face ) * numfaces );
+ binobj->BSPTree = (ODT_BSPNode *)
+ ( (char *) binobj->VisPolyList + sizeof( ODT_VisPolys ) + sizeof( dword ) * numpolygons );
+
+ // calculate bounding sphere for object
+ double maxx = -100000; double minx = 100000;
+ double maxy = -100000; double miny = 100000;
+ double maxz = -100000; double minz = 100000;
+ double maxsphere = 0;
+ int i = 0;
+ for ( i = 0; i < numvertices; i++ ) {
+ // calc bounding sphere
+ double ctlength = ( (Vector3) vtxlist[ i ] ).VecLength();
+ if ( ctlength > maxsphere )
+ maxsphere = ctlength;
+ // calc bounding box
+ if ( vtxlist[ i ].getX() > maxx ) maxx = vtxlist[ i ].getX();
+ if ( vtxlist[ i ].getY() > maxy ) maxy = vtxlist[ i ].getY();
+ if ( vtxlist[ i ].getZ() > maxz ) maxz = vtxlist[ i ].getZ();
+ if ( vtxlist[ i ].getX() < minx ) minx = vtxlist[ i ].getX();
+ if ( vtxlist[ i ].getY() < miny ) miny = vtxlist[ i ].getY();
+ if ( vtxlist[ i ].getZ() < minz ) minz = vtxlist[ i ].getZ();
+ }
+
+ maxsphere *= VERTEX_SCALE_FAC;
+ binobj->BoundingSphere = FLOAT_TO_FIXED( maxsphere );
+ binobj->BoundingSphere2 = FLOAT_TO_FIXED( maxsphere * maxsphere );
+
+ // fill vertex list -----------------------------------
+ ODT_Vertex3 *vfillp = binobj->VertexList;
+ // store face normals first
+ for ( i = 0; i < numnormals; i++, vfillp++ ) {
+ Vector3 normal( facelist[ i ].getPlaneNormal() );
+ vfillp->X = FLOAT_TO_FIXED( normal.getX() );
+ vfillp->Y = FLOAT_TO_FIXED( -normal.getY() );
+ vfillp->Z = FLOAT_TO_FIXED( -normal.getZ() );
+ vfillp->Flags = 0x00000000L;
+ }
+ // store real vertices after face normals
+ for ( i = 0; i < numvertices; i++, vfillp++ ) {
+ vfillp->X = FLOAT_TO_FIXED( vtxlist[ i ].getX() * VERTEX_SCALE_FAC );
+ vfillp->Y = FLOAT_TO_FIXED( -vtxlist[ i ].getY() * VERTEX_SCALE_FAC );
+ vfillp->Z = FLOAT_TO_FIXED( -vtxlist[ i ].getZ() * VERTEX_SCALE_FAC );
+ vfillp->Flags = 0x00000000L;
+ }
+
+ // build flat bsp tree if not available
+ if ( BSPTreeAvailable() && !BSPTreeFlatAvailable() ) {
+ //TODO:
+ // implement flat->linked
+ }
+
+ // fill polygon array and vertex index arrays----------
+ ODT_Poly *pfillp = binobj->PolyList;
+ char *vertbase = (char *) pfillp + sizeof( ODT_Poly ) * numpolygons;
+ int countofs = 0;
+ if ( BSPTreeFlatAvailable() ) {
+ // scan polygons of flat bsp tree
+ int numnodes = bsptreeflat.getNumNodes();
+ for ( i = 1; i <= numnodes; i++ ) {
+ // node zero does not correspond to any polygon
+ // and is also not included in the number of nodes!
+ BSPNodeFlat *node = bsptreeflat.FetchNodePerId( i );
+ Polygon *polyscan = node->getPolygon();
+ int polyno = polyscan->getId();
+ pfillp[ polyno ].NumVerts = polyscan->getNumVertices();
+ pfillp[ polyno ].FaceIndx = polyscan->getFaceId();
+ pfillp[ polyno ].VertIndxs = (dword *) polyscan;
+ }
+ // scan polygons once again to assign vertex index lists
+ // in order instead of in the order of bsp nodes
+ for ( i = 1; i <= numnodes; i++, pfillp++ ) {
+ Polygon *polyscan = (Polygon *) pfillp->VertIndxs;
+ pfillp->VertIndxs = (dword *) ( vertbase + countofs );
+ // fill in array of vertex indexes
+ polyscan->FillVertexIndexArray( pfillp->VertIndxs );
+ countofs += sizeof( dword ) * pfillp->NumVerts;
+ }
+ } else {
+ // scan entire polygon list
+ Polygon *polyscan = polylist.FetchHead();
+ for ( i = 0; i < polylist.getNumElements(); i++, polyscan = polyscan->getNext(), pfillp++ ) {
+ pfillp->NumVerts = polyscan->getNumVertices();
+ pfillp->FaceIndx = polyscan->getFaceId();
+ pfillp->VertIndxs = (dword *) ( vertbase + countofs );
+ // fill in array of vertex indexes
+ polyscan->FillVertexIndexArray( pfillp->VertIndxs );
+ countofs += sizeof( dword ) * pfillp->NumVerts;
+ }
+ }
+ // correct vertex indexes to take face normals into account
+ dword *dfillp = (dword *) vertbase;
+ for ( i = 0; i < numvertexindices; i++ )
+ *dfillp++ += numnormals;
+
+ //NOTE:
+ // the object contains a pointer to the polygon list.
+ // this list contains all the polygon structures (no vertex indexes!)
+ // the vertex index lists for all the polygons of the object follow
+ // contiguously after all the polygon structures.
+
+ // fill face list (defines surface properties) --------
+ ODT_Face *ffillp = binobj->FaceList;
+ for ( i = 0; i < numfaces; i++, ffillp++ ) {
+ ffillp->TexMap = NULL;
+ ffillp->TexEqui = NULL;
+ ffillp->ColorRGB = 0;
+ ffillp->ColorIndx = 0;
+ ffillp->FaceNormalIndx = i;
+ ffillp->Shading = facelist[ i ].getShadingType() & Face::base_mask;
+
+ // write color if any attached and valid
+ if ( facelist[ i ].getShadingType() & Face::color_mask ) {
+ int coltype = facelist[ i ].getColorType();
+ if ( coltype == Face::indexed_col ) {
+ dword colindx;
+ facelist[ i ].getColorIndex( colindx );
+ ffillp->ColorIndx = ( ( ( ( ( colindx << 8 ) + colindx ) << 8 ) + colindx ) << 8 ) + colindx;
+ } else if ( coltype == Face::rgb_col ) {
+ ColorRGBA coltuple;
+ facelist[ i ].getColorRGBA( coltuple );
+ dword colrgb = ( ( ( ( ( coltuple.A << 8 ) + coltuple.B ) << 8 ) + coltuple.G ) << 8 ) + coltuple.R;
+ ffillp->ColorRGB = colrgb;
+ }
+ }
+
+ // attach texture
+ if ( facelist[ i ].getShadingType() & Face::texmap_mask ) {
+ const char *texname = facelist[ i ].getTextureName();
+ // simply store name and calc mapping
+ ffillp->TexMap = (char *) texname;
+ ODT_CalcAffineMapping( facelist[ i ], (dword *) ffillp->TexXmatrx );
+ }
+ }
+
+ // create bsp tree in object structure
+ if ( BSPTreeFlatAvailable() ) {
+ ODT_BSPNode *curbspnode = binobj->BSPTree + 1; // skip node at pos zero
+ for ( int i = 1; i <= bsptreeflat.getNumNodes(); i++, curbspnode++ ) {
+ BSPNodeFlat *node = bsptreeflat.FetchNodePerId( i );
+ curbspnode->Polygon = node->getPolygon()->getId();
+ curbspnode->Contained = node->getContainedList();
+ //curbspnode->BackList= node->getBackList(); //NOTE: not implemented!
+ curbspnode->FrontTree = node->getFrontSubTree();
+ curbspnode->BackTree = node->getBackSubTree();
+ }
+ }
+
+ memblocksize = objectmemsize;
+ return (byte *) binobj;
+}
+
+
+// create object that can be saved to file as single block (ODT format) -------
+//
+byte *ObjectBinFormat::ODT_CreateFileObject( int& memblocksize, byte *engineobj )
+{
+ ODT_GenObject *binobj = (ODT_GenObject *) engineobj;
+ TextureChunk& texlist = getTextureList();
+
+ // create table of texture names
+ char **texnameaddxs;
+ char *texturenames, *nexttexname;
+ int numtextures = texlist.getNumElements();
+ int texnamesize = 0;
+ int i = 0;
+ if ( numtextures > 0 ) {
+ for ( i = 0; i < numtextures; i++ )
+ texnamesize += strlen( texlist[ i ].getName() ) + 1;
+ texturenames = new char[ texnamesize ];
+ nexttexname = texturenames;
+ texnameaddxs = new char*[ numtextures ];
+ for ( i = 0; i < numtextures; i++ ) {
+ strcpy( nexttexname, texlist[ i ].getName() );
+ texnameaddxs[ i ] = nexttexname;
+ nexttexname += strlen( nexttexname ) + 1;
+ }
+ }
+
+ // correct texture pointers to point to texture names in block
+ ODT_Face *facescan = binobj->FaceList;
+ dword j = 0;
+ for ( j = 0; j < binobj->NumFaces; j++, facescan++ )
+ if ( facescan->TexMap != NULL )
+ for ( int k = 0; k < numtextures; k++ )
+ if ( strcmp( texnameaddxs[ k ], facescan->TexMap ) == 0 ) {
+// delete facescan->TexMap; // legacy
+ facescan->TexMap = (char *)
+ ( (ptrdiff_t) texnameaddxs[ k ] - (ptrdiff_t) texturenames + memblocksize );
+ break;
+ }
+
+ // make absolute pointers to vertex index lists header relative
+ ODT_Poly *polylist = binobj->PolyList;
+ for ( j = 0; j < binobj->NumPolys; j++, polylist++ ) {
+ polylist->VertIndxs = (dword *) ( (ptrdiff_t) polylist->VertIndxs - (ptrdiff_t) binobj );
+ }
+
+ // correct absolute pointers in object header to header-relative pointers
+ binobj->VertexList = (ODT_Vertex3 *) ( (ptrdiff_t) binobj->VertexList - (ptrdiff_t) binobj );
+ binobj->X_VertexList = (ODT_Vertex3 *) ( (ptrdiff_t) binobj->X_VertexList - (ptrdiff_t) binobj );
+ binobj->P_VertexList = (ODT_ProjPoint *) ( (ptrdiff_t) binobj->P_VertexList - (ptrdiff_t) binobj );
+ binobj->S_VertexList = (ODT_SPoint *) ( (ptrdiff_t) binobj->S_VertexList - (ptrdiff_t) binobj );
+ binobj->PolyList = (ODT_Poly *) ( (ptrdiff_t) binobj->PolyList - (ptrdiff_t) binobj );
+ binobj->FaceList = (ODT_Face *) ( (ptrdiff_t) binobj->FaceList - (ptrdiff_t) binobj );
+ binobj->VisPolyList = (ODT_VisPolys *) ( (ptrdiff_t) binobj->VisPolyList - (ptrdiff_t) binobj );
+ binobj->BSPTree = (ODT_BSPNode *) ( (ptrdiff_t) binobj->BSPTree - (ptrdiff_t) binobj );
+
+ // create block
+ byte *block = new byte[ memblocksize + texnamesize ];
+ memcpy( block, binobj, memblocksize );
+ if ( texnamesize > 0 ) {
+ memcpy( block + memblocksize, texturenames, texnamesize );
+ memblocksize += texnamesize;
+ // free texture name table
+ delete texturenames;
+ delete texnameaddxs;
+ }
+
+ return block;
+}
+
+
+// ----------------------------------------------------------------------------
+//
+#define DOUBLE_TO_OD2FLOAT(x) (float)(x)
+
+
+// calculate affine mapping using face's mapping specification ----------------
+//
+void ObjectBinFormat::OD2_CalcAffineMapping( Face& face, dword *dmatrx )
+{
+ Vertex2 vtx;
+ double mat[3][3];
+ int i = 0;
+ // build xyw-matrix
+ for ( i = 0; i < 3; i++ ) {
+ vtx = face.MapXY( i );
+ mat[ 0 ][ i ] = vtx.getX() * VERTEX_SCALE_FAC;
+ mat[ 1 ][ i ] = vtx.getY() * -VERTEX_SCALE_FAC;
+ mat[ 2 ][ i ] = vtx.getW() * -VERTEX_SCALE_FAC;
+ }
+ Transform2 xyw( (const double(*)[3]) mat );
+
+ // build uv1-matrix
+ for ( i = 0; i < 3; i++ ) {
+ vtx = face.MapUV( i );
+ mat[ 0 ][ i ] = vtx.getX();
+ mat[ 1 ][ i ] = vtx.getY();
+ mat[ 2 ][ i ] = vtx.getW();
+ }
+ Transform2 uv1( (const double(*)[3]) mat );
+
+ // invert uv1
+ Transform2 uv1i;
+ if ( !uv1.Inverse( uv1i ) ) {
+ ErrorMessage( "ObjectBinFormat::OD2_CalcAffineMapping(): Collinear mapping coordinates encountered!" );
+ }
+
+ // calculate affine mapping
+ Transform2 map( xyw );
+ map.Concat( uv1i );
+ // store result into destination structure (9 coefficients)
+ double (*affinemap)[ 3 ] = ( double (*)[3] ) map.LinMatrixAccess();
+ float (*dest)[ 4 ] = (float (*)[4]) dmatrx;
+ for ( i = 0; i < 3; i++ ) {
+
+ dest[ i ][ 0 ] = DOUBLE_TO_OD2FLOAT( affinemap[ i ][ 0 ] );
+ dest[ i ][ 1 ] = DOUBLE_TO_OD2FLOAT( affinemap[ i ][ 1 ] );
+ dest[ i ][ 2 ] = DOUBLE_TO_OD2FLOAT( 0.0 );
+ dest[ i ][ 3 ] = DOUBLE_TO_OD2FLOAT( affinemap[ i ][ 2 ] );
+
+ OD2_Geomv_out( &dest[ i ][ 0 ] );
+ OD2_Geomv_out( &dest[ i ][ 1 ] );
+ OD2_Geomv_out( &dest[ i ][ 2 ] );
+ OD2_Geomv_out( &dest[ i ][ 3 ] );
+ }
+}
+
+
+// create object recognizeable by engine (ODT format) -------------------------
+//
+byte *ObjectBinFormat::OD2_CreateEngineObject( int& memblocksize )
+{
+ // fetch object data lists
+ VertexChunk& vtxlist = getVertexList();
+ PolygonList& polylist = getPolygonList();
+ FaceChunk& facelist = getFaceList();
+ TextureChunk& texlist = getTextureList();
+
+ // calculate some basic numbers
+ int numvertices = getNumVertices();
+ int numnormals = getNumNormals();
+ int numallvtxs = numvertices + numnormals;
+ int numpolygons = BSPTreeAvailable() ? getBspPolygons() : getNumPolygons();
+ int numfaces = getNumFaces();
+ int numbspnodes = getBspPolygons();
+
+ // count number of vertices of all polygons
+ int numvertexindices = 0;
+ if ( BSPTreeAvailable() )
+ bsptree->SumVertexNums( numvertexindices );
+ else
+ numvertexindices = polylist.FetchHead()->SumVertexNumsEntireList();
+
+ // calculate size of entire object structure
+ size_t objectmemsize = sizeof( OD2_Root ) + // generic object header
+ sizeof( ODT_Vertex3 ) * numallvtxs + // object space vertices
+ sizeof( ODT_Poly ) * numpolygons + // polygon control data
+ sizeof( dword ) * numvertexindices + // polygon vertindx lists
+ sizeof( OD2_Face ) * numfaces; // face control data
+
+ // allocate memory for all object data (only excluding texturemaps)
+ OD2_Root *binobj = (OD2_Root *) new char[ objectmemsize ];
+ memset( binobj, 0x00, objectmemsize );
+
+ // fill in objectheader
+ strcpy( binobj->odt2, "ODT2\0" );
+ binobj->major = 1;
+ binobj->minor = 0;
+ binobj->rootflags = 0x0000;
+ binobj->rootflags2 = 0x0000;
+ binobj->NodeList = NULL;
+ binobj->Children[ 0 ] = NULL;
+ binobj->Children[ 1 ] = NULL;
+ binobj->InstanceSize = SWAP_32( sizeof( OD2_Root ) );
+ binobj->NumVerts = SWAP_32( numallvtxs );
+ binobj->NumPolyVerts = SWAP_32( numvertices );
+ binobj->NumNormals = SWAP_32( numnormals );
+ binobj->VertexList = (OD2_Vertex3 *) ( binobj + 1 );
+ binobj->NumPolys = numpolygons;
+ binobj->PolyList = (OD2_Poly *)
+ ( (char *) binobj->VertexList + sizeof( OD2_Vertex3 ) * numallvtxs );
+ binobj->NumFaces = numfaces;
+ binobj->FaceList = (OD2_Face *)
+ ( (char *) binobj->PolyList + sizeof( OD2_Poly ) * numpolygons + sizeof( dword ) * numvertexindices );
+ binobj->NumTextures = 0; // must be set later on
+
+ // calculate bounding sphere for object
+ double maxx = -100000; double minx = 100000;
+ double maxy = -100000; double miny = 100000;
+ double maxz = -100000; double minz = 100000;
+ double maxsphere = 0;
+ int i = 0;
+ for ( i = 0; i < numvertices; i++ ) {
+ // calc bounding sphere
+ double ctlength = ( (Vector3) vtxlist[ i ] ).VecLength();
+ if ( ctlength > maxsphere )
+ maxsphere = ctlength;
+ // calc bounding box
+ if ( vtxlist[ i ].getX() > maxx ) maxx = vtxlist[ i ].getX();
+ if ( vtxlist[ i ].getY() > maxy ) maxy = vtxlist[ i ].getY();
+ if ( vtxlist[ i ].getZ() > maxz ) maxz = vtxlist[ i ].getZ();
+ if ( vtxlist[ i ].getX() < minx ) minx = vtxlist[ i ].getX();
+ if ( vtxlist[ i ].getY() < miny ) miny = vtxlist[ i ].getY();
+ if ( vtxlist[ i ].getZ() < minz ) minz = vtxlist[ i ].getZ();
+ }
+
+ maxsphere *= VERTEX_SCALE_FAC;
+ binobj->BoundingSphere = DOUBLE_TO_OD2FLOAT( maxsphere );
+ OD2_Geomv_out( &binobj->BoundingSphere );
+
+ // fill vertex list -----------------------------------
+ OD2_Vertex3 *vfillp = binobj->VertexList;
+ // store face normals first
+ for ( i = 0; i < numnormals; i++, vfillp++ ) {
+ Vector3 normal( facelist[ i ].getPlaneNormal() );
+
+ vfillp->X = DOUBLE_TO_OD2FLOAT( normal.getX() );
+ vfillp->Y = DOUBLE_TO_OD2FLOAT( -normal.getY() );
+ vfillp->Z = DOUBLE_TO_OD2FLOAT( -normal.getZ() );
+
+ OD2_Geomv_out( &vfillp->X );
+ OD2_Geomv_out( &vfillp->Y );
+ OD2_Geomv_out( &vfillp->Z );
+
+ vfillp->Flags = SWAP_32( 0x00000000L );
+ }
+ // store real vertices after face normals
+ for ( i = 0; i < numvertices; i++, vfillp++ ) {
+
+ vfillp->X = DOUBLE_TO_OD2FLOAT( vtxlist[ i ].getX() * VERTEX_SCALE_FAC );
+ vfillp->Y = DOUBLE_TO_OD2FLOAT( -vtxlist[ i ].getY() * VERTEX_SCALE_FAC );
+ vfillp->Z = DOUBLE_TO_OD2FLOAT( -vtxlist[ i ].getZ() * VERTEX_SCALE_FAC );
+
+ OD2_Geomv_out( &vfillp->X );
+ OD2_Geomv_out( &vfillp->Y );
+ OD2_Geomv_out( &vfillp->Z );
+
+ vfillp->Flags = SWAP_32( 0x00000000L );
+ }
+
+ // fill polygon array and vertex index arrays----------
+ OD2_Poly *pfillp = binobj->PolyList;
+ char *vertbase = (char *) pfillp + sizeof( OD2_Poly ) * numpolygons;
+ int countofs = 0;
+ // scan entire polygon list
+ Polygon *polyscan = polylist.FetchHead();
+ for ( i = 0; i < polylist.getNumElements(); i++, polyscan = polyscan->getNext(), pfillp++ ) {
+ pfillp->NumVerts = polyscan->getNumVertices();
+ pfillp->FaceIndx = SWAP_32( polyscan->getFaceId() );
+ pfillp->VertIndxs = (dword *) ( vertbase + countofs );
+ // fill in array of vertex indexes
+ polyscan->FillVertexIndexArray( pfillp->VertIndxs );
+
+ countofs += sizeof( dword ) * pfillp->NumVerts;
+
+ pfillp->NumVerts = SWAP_32( pfillp->NumVerts );
+ }
+
+
+ // correct vertex indexes to take face normals into account
+ dword *dfillp = (dword *) vertbase;
+ for ( i = 0; i < numvertexindices; i++ ) {
+ *dfillp += numnormals;
+ *dfillp = SWAP_32( *dfillp );
+ dfillp++;
+ }
+
+ //NOTE:
+ // the object contains a pointer to the polygon list.
+ // this list contains all the polygon structures (no vertex indexes!)
+ // the vertex index lists for all the polygons of the object follow
+ // contiguously after all the polygon structures.
+
+ // fill face list (defines surface properties) --------
+ OD2_Face *ffillp = binobj->FaceList;
+ for ( i = 0; i < numfaces; i++, ffillp++ ) {
+ ffillp->TexMap = NULL;
+ ffillp->ColorRGB = 0;
+ ffillp->ColorIndx = 0;
+ ffillp->FaceNormalIndx = SWAP_32( i );
+ ffillp->Shading = SWAP_32( facelist[ i ].getShadingType() & Face::base_mask );
+
+ // write color if any attached and valid
+ if ( facelist[ i ].getShadingType() & Face::color_mask ) {
+ int coltype = facelist[ i ].getColorType();
+ if ( coltype == Face::indexed_col ) {
+ dword colindx;
+ facelist[ i ].getColorIndex( colindx );
+ ffillp->ColorIndx = SWAP_32( ( ( ( ( ( colindx << 8 ) + colindx ) << 8 ) + colindx ) << 8 ) + colindx);
+ } else if ( coltype == Face::rgb_col ) {
+ ColorRGBA coltuple;
+ facelist[ i ].getColorRGBA( coltuple );
+ dword colrgb = ( ( ( ( ( coltuple.A << 8 ) + coltuple.B ) << 8 ) + coltuple.G ) << 8 ) + coltuple.R;
+ ffillp->ColorRGB = SWAP_32( colrgb );
+ }
+ }
+
+ // attach texture
+ if ( facelist[ i ].getShadingType() & Face::texmap_mask ) {
+ const char *texname = facelist[ i ].getTextureName();
+ // simply store name and calc mapping
+ ffillp->TexMap = (char *) texname;
+ OD2_CalcAffineMapping( facelist[ i ], (dword *) ffillp->TexXmatrx );
+ }
+ }
+
+ memblocksize = objectmemsize;
+ return (byte *) binobj;
+}
+
+
+// create object that can be saved to file as single block (OD2 format) -------
+//
+byte *ObjectBinFormat::OD2_CreateFileObject( int& memblocksize, byte *engineobj )
+{
+ OD2_Root *binobj = (OD2_Root *) engineobj;
+ TextureChunk& texlist = getTextureList();
+
+ // create table of texture names
+ char **texnameaddxs;
+ char *texturenames, *nexttexname;
+ int numtextures = texlist.getNumElements();
+ int texnamesize = 0;
+ int i = 0;
+ if ( numtextures > 0 ) {
+ for ( i = 0; i < numtextures; i++ )
+ texnamesize += strlen( texlist[ i ].getName() ) + 1;
+ texturenames = new char[ texnamesize ];
+ nexttexname = texturenames;
+ texnameaddxs = new char*[ numtextures ];
+ for ( i = 0; i < numtextures; i++ ) {
+ strcpy( nexttexname, texlist[ i ].getName() );
+ texnameaddxs[ i ] = nexttexname;
+ nexttexname += strlen( nexttexname ) + 1;
+ }
+ }
+
+ // store number of textures
+ binobj->NumTextures = SWAP_32( numtextures );
+
+ // correct texture pointers to point to texture names in block
+ OD2_Face *facescan = binobj->FaceList;
+ dword j = 0;
+ for ( j = 0; j < binobj->NumFaces; j++, facescan++ )
+ if ( facescan->TexMap != NULL )
+ for ( int k = 0; k < numtextures; k++ )
+ if ( strcmp( texnameaddxs[ k ], facescan->TexMap ) == 0 ) {
+// delete facescan->TexMap; // legacy
+ facescan->TexMap = (char *) SWAP_32( ( (ptrdiff_t) texnameaddxs[ k ] - (ptrdiff_t) texturenames + memblocksize ) );
+ break;
+ }
+
+ binobj->NumFaces = SWAP_32( binobj->NumFaces );
+
+ // make absolute pointers to vertex index lists header relative
+ OD2_Poly *polylist = binobj->PolyList;
+ for ( j = 0; j < binobj->NumPolys; j++, polylist++ ) {
+ polylist->VertIndxs = (dword *) SWAP_32( ( (ptrdiff_t) polylist->VertIndxs - (ptrdiff_t) binobj ) );
+ }
+
+ binobj->NumPolys = SWAP_32( binobj->NumPolys );
+
+ // correct absolute pointers in object header to header-relative pointers
+// binobj->NodeList = (OD2_Node *) SWAP_32( (ptrdiff_t) binobj->NodeList - (ptrdiff_t) binobj );
+// binobj->Children[0] = (OD2_Child *) SWAP_32( (ptrdiff_t) binobj->Children[0] - (ptrdiff_t) binobj );
+// binobj->Children[1] = (OD2_Child *) SWAP_32( (ptrdiff_t) binobj->Children[1] - (ptrdiff_t) binobj );
+ binobj->VertexList = (OD2_Vertex3 *) SWAP_32( (ptrdiff_t) binobj->VertexList - (ptrdiff_t) binobj );
+ binobj->PolyList = (OD2_Poly *) SWAP_32( (ptrdiff_t) binobj->PolyList - (ptrdiff_t) binobj );
+ binobj->FaceList = (OD2_Face *) SWAP_32( (ptrdiff_t) binobj->FaceList - (ptrdiff_t) binobj );
+
+ // create block
+ byte *block = new byte[ memblocksize + texnamesize ];
+ memcpy( block, binobj, memblocksize );
+ if ( texnamesize > 0 ) {
+ memcpy( block + memblocksize, texturenames, texnamesize );
+ memblocksize += texnamesize;
+ // free texture name table
+ delete texturenames;
+ delete texnameaddxs;
+ }
+
+ return block;
+}
+
+
+// write entire object as binary file -----------------------------------------
+//
+int ObjectBinFormat::WriteDataToFile( const char *filename, int format )
+{
+ // to be filled
+ int memblocksize;
+ byte* engineobj = NULL;
+ byte* fileobj = NULL;
+
+ if ( format == BINFORMAT_ODT ) {
+
+ sprintf( line, "Writing object data to ODT file: \"%s\"...\n", filename );
+ InfoMessage( line );
+
+ // create object as binary block
+ engineobj = ODT_CreateEngineObject( memblocksize );
+
+ // convert object to destination file format
+ fileobj = ODT_CreateFileObject( memblocksize, engineobj );
+
+ } else if ( format == BINFORMAT_OD2 ) {
+
+ sprintf( line, "Writing object data to OD2 file: \"%s\"...\n", filename );
+ InfoMessage( line );
+
+ // create object as binary block
+ engineobj = OD2_CreateEngineObject( memblocksize );
+
+ // convert object to destination file format
+ fileobj = OD2_CreateFileObject( memblocksize, engineobj );
+
+ } else {
+ return FALSE;
+ }
+
+ // write binary object representation to file
+ int wstat = 0;
+ {
+ FileAccess ofile( filename, "wb" );
+ ofile.Write( fileobj, 1, memblocksize );
+ wstat = ofile.Status();
+ }
+
+ // free binary object memory blocks
+ delete fileobj;
+ delete engineobj;
+
+ return ( wstat == SYSTEM_IO_OK );
+}
+
+
+// string scratchpad ----------------------------------------------------------
+//
+char ObjectBinFormat::line[ 128 ] = "";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/ObjectBinFormat.h b/tool_src/BspLib/ObjectBinFormat.h
new file mode 100644
index 0000000..0810318
--- /dev/null
+++ b/tool_src/BspLib/ObjectBinFormat.h
@@ -0,0 +1,55 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: ObjectBinFormat.h
+//
+// Copyright (c) 1998-1999 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _OBJECTBINFORMAT_H_
+#define _OBJECTBINFORMAT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// BspObject capable of writing itself in binary format -----------------------
+//
+class ObjectBinFormat : public BspObject, public virtual SystemIO {
+
+public:
+
+ // output formats
+ enum {
+ BINFORMAT_ODT, // ODT (old format: single object)
+ BINFORMAT_OD2, // OD2 (new format: scene/tree)
+ };
+
+public:
+ ObjectBinFormat( BspObject& object ) : BspObject( object ) { }
+ ~ObjectBinFormat() { }
+ int WriteDataToFile( const char *filename, int format );
+
+private:
+ void ODT_CalcAffineMapping( Face& face, dword *dmatrx );
+ byte * ODT_CreateEngineObject( int& memblocksize );
+ byte * ODT_CreateFileObject( int& memblocksize, byte *engineobj );
+
+ void OD2_CalcAffineMapping( Face& face, dword *dmatrx );
+ byte * OD2_CreateEngineObject( int& memblocksize );
+ byte * OD2_CreateFileObject( int& memblocksize, byte *engineobj );
+
+private:
+ static char line[]; // scratchpad
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _OBJECTBINFORMAT_H_
+
diff --git a/tool_src/BspLib/ObjectBspFormat.cpp b/tool_src/BspLib/ObjectBspFormat.cpp
new file mode 100644
index 0000000..12082f0
--- /dev/null
+++ b/tool_src/BspLib/ObjectBspFormat.cpp
@@ -0,0 +1,213 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: ObjectBspFormat.cpp
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "ObjectBspFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// write list of vertices -----------------------------------------------------
+//
+int ObjectBspFormat::WriteVertexList( FileAccess& output )
+{
+ if ( numvertices > 0 ) {
+
+ output.WriteLine( "; list of all vertices comprising the object -----------------------------\n" );
+ output.WriteLine( "; numbering starts with 1\n" );
+
+ sprintf( line, "%s\n", _vertices_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numvertices; i++ ) {
+ sprintf( line, "%f,\t%f,\t%f\t; %d\n",
+ vertexlist[ i ].getX(),
+ vertexlist[ i ].getY(),
+ vertexlist[ i ].getZ(),
+ i + 1 );
+ output.WriteLine( line );
+ }
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write list of polygons -----------------------------------------------------
+//
+int ObjectBspFormat::WritePolygonList( FileAccess& output )
+{
+ if ( numbsppolygons > 0 ) {
+
+ output.WriteLine( "; list of all polygons (faces split into pieces by bsp compiler) ---------\n" );
+ output.WriteLine( "; numbering starts with 1\n" );
+
+ sprintf( line, "%s\n", _polygons_str );
+ output.WriteLine( line );
+
+ int i = 0;
+ Polygon *poly;
+ while ( !bsptree.TreeEmpty() && ( ( poly = bsptree->FetchBSPPolygon( i ) ) != NULL ) ) {
+ poly->WriteVertexList( output, FALSE );
+ sprintf( line, "\t\t; %d\n", ++i );
+ output.WriteLine( line );
+ }
+ output.WriteLine( "\n" );
+
+ if ( i < numpolygons_before_bsp )
+ ErrorMessage( "***ERROR*** Polygon missing in BSP tree (ObjectBspFormat::WritePolygonList())." );
+ }
+
+ return output.Status();
+}
+
+
+// write list of faces (each face consists of one to many polygons) -----------
+//
+int ObjectBspFormat::WriteFaceList( FileAccess& output )
+{
+ if ( numfaces > 0 ) {
+
+ output.WriteLine( "; list of polygons comprising each face ----------------------------------\n" );
+ output.WriteLine( "; numbering starts with 1\n" );
+
+ sprintf( line, "%s\n", _faces_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numfaces; i++ ) {
+ PolygonList facepolylist( this );
+ if ( !bsptree.TreeEmpty() )
+ bsptree->FetchFacePolygons( i, facepolylist );
+ facepolylist.WritePolyList( output, i + 1 );
+ }
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write surface properties of faces ------------------------------------------
+//
+int ObjectBspFormat::WriteFaceProperties( FileAccess& output )
+{
+ if ( numfaces > 0 ) {
+
+ output.WriteLine( "; face material properties (color, texture, etc.) ------------------------\n" );
+
+ sprintf( line, "%s\n", _faceproperties_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numfaces; i++ )
+ facelist[ i ].WriteFaceInfo( output );
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write face normals ---------------------------------------------------------
+//
+int ObjectBspFormat::WriteNormals( FileAccess& output )
+{
+ if ( numnormals > 0 ) {
+
+ output.WriteLine( "; face normals -----------------------------------------------------------\n" );
+
+ sprintf( line, "%s\n", _facenormals_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numfaces /*numnormals*/; i++ )
+ facelist[ i ].WriteNormalInfo( output );
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// write list of textures -----------------------------------------------------
+//
+int ObjectBspFormat::WriteTextureList( FileAccess& output )
+{
+ if ( numtextures > 0 ) {
+
+ output.WriteLine( "; texture definitions (sizes and filenames) ------------------------------\n" );
+
+ sprintf( line, "%s\n", _textures_str );
+ output.WriteLine( line );
+
+ for ( int i = 0; i < numtextures; i++ )
+ texturelist[ i ].WriteInfo( output );
+ }
+
+ return output.Status();
+}
+
+
+// write list of mapping coordinates (correspondences) ------------------------
+//
+int ObjectBspFormat::WriteMappingList( FileAccess& output )
+{
+ if ( numtexmappedfaces > 0 ) {
+
+ output.WriteLine( "; mapping parameters for textured faces ----------------------------------\n" );
+ sprintf( line, "%s\n", _correspondences_str );
+ output.WriteLine( line );
+ output.WriteLine( "\n" );
+
+ int curfaceno = 0;
+ for ( int i = 0; i < numtexmappedfaces; i++, curfaceno++ ) {
+ while ( !facelist[ curfaceno ].FaceTexMapped() )
+ curfaceno++;
+ sprintf( line, "; correspondence %d (face %d)\n", i + 1, curfaceno + 1 );
+ output.WriteLine( line );
+
+ facelist[ curfaceno ].WriteMappingInfo( output );
+ }
+ }
+
+ return output.Status();
+}
+
+
+// write textual representation of bsp tree to output file --------------------
+//
+int ObjectBspFormat::WriteBSPTree( FileAccess& output )
+{
+ if ( !bsptree.TreeEmpty() ) {
+
+ output.WriteLine( "; polygon bsp tree -------------------------------------------------------\n" );
+
+ sprintf( line, "%s\n", _bsptree_str );
+ output.WriteLine( line );
+
+ bsptree->WriteBSPTree( output );
+
+ output.WriteLine( "\n" );
+ }
+
+ return output.Status();
+}
+
+
+// string scratchpad ----------------------------------------------------------
+//
+char ObjectBspFormat::line[ 1024 ] = "";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/ObjectBspFormat.h b/tool_src/BspLib/ObjectBspFormat.h
new file mode 100644
index 0000000..7d599eb
--- /dev/null
+++ b/tool_src/BspLib/ObjectBspFormat.h
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: ObjectBspFormat.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _OBJECTBSPFORMAT_H_
+#define _OBJECTBSPFORMAT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "BspFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// BspObject capable of BspFormat I/O operations ------------------------------
+//
+class ObjectBspFormat : public BspObject, public BspFormat {
+
+public:
+ ObjectBspFormat( BspObject& object, BspFormat& format );
+ ~ObjectBspFormat() { }
+
+ virtual int WriteVertexList( FileAccess& output );
+ virtual int WritePolygonList( FileAccess& output );
+ virtual int WriteFaceList( FileAccess& output );
+ virtual int WriteFaceProperties( FileAccess& output );
+ virtual int WriteTextureList( FileAccess& output );
+ virtual int WriteMappingList( FileAccess& output );
+ virtual int WriteNormals( FileAccess& output );
+ virtual int WriteBSPTree( FileAccess& output );
+
+private:
+ static char line[]; // scratchpad
+};
+
+// construct by copying base class objects ------------------------------------
+inline ObjectBspFormat::ObjectBspFormat( BspObject& object, BspFormat& format ) :
+ BspObject( object ),
+ BspFormat( format )
+{
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _OBJECTBSPFORMAT_H_
+
diff --git a/tool_src/BspLib/OutputData3D.cpp b/tool_src/BspLib/OutputData3D.cpp
new file mode 100644
index 0000000..f4e27d5
--- /dev/null
+++ b/tool_src/BspLib/OutputData3D.cpp
@@ -0,0 +1,105 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: OutputData3D.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "OutputData3D.h"
+#include "AodOutput.h"
+#include "BspOutput.h"
+//#include "VrmlOutput.h"
+
+//#define VRML_OUTPUT_POSSIBLE
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// "virtual" constructor for different output format objects ------------------
+//
+OutputData3D::OutputData3D( BspObjectList objectlist, const char *filename, int format ) :
+ IOData3D( objectlist, String( filename ) ),
+ m_data( NULL )
+{
+ // create "real" output object according to specified format of output file
+ if ( format != DONT_CREATE_OBJECT ) {
+ switch ( m_objectformat = format ) {
+
+ case AOD_FORMAT_1_1:
+ m_data = new AodOutput( objectlist, filename );
+ break;
+
+ case BSP_FORMAT_1_1:
+ m_data = new BspOutput( objectlist, filename );
+ break;
+
+#ifdef VRML_OUTPUT_POSSIBLE
+ case VRML_FORMAT_1_0:
+ m_data = new VrmlFile( objectlist, filename );
+ break;
+#endif
+ default:
+ ErrorMessage( "[OutputData3D]: Unrecognized output file format." );
+ m_objectformat = UNKNOWN_FORMAT;
+ }
+ } else {
+ m_objectformat = DONT_CREATE_OBJECT;
+ }
+}
+
+
+// constructor using an InputData3D object directly to get data ---------------
+//
+OutputData3D::OutputData3D( const InputData3D& inputdata, int format ) :
+ IOData3D( inputdata.getObjectList(), inputdata.getFileName() ),
+ m_data( NULL )
+{
+ // create "real" output object according to specified format of output file
+ if ( format != DONT_CREATE_OBJECT ) {
+ switch ( m_objectformat = format ) {
+
+ case AOD_FORMAT_1_1:
+ m_data = new AodOutput( inputdata );
+ break;
+
+ case BSP_FORMAT_1_1:
+ m_data = new BspOutput( inputdata );
+ break;
+
+#ifdef VRML_OUTPUT_POSSIBLE
+ case VRML_FORMAT_1_0:
+ m_data = new VrmlFile( inputdata );
+ break;
+#endif
+ default:
+ ErrorMessage( "[OutputData3D]: Unrecognized output file format." );
+ m_objectformat = UNKNOWN_FORMAT;
+ }
+ } else {
+ m_objectformat = DONT_CREATE_OBJECT;
+ }
+}
+
+
+// virtual destructor ---------------------------------------------------------
+//
+OutputData3D::~OutputData3D()
+{
+ // delete "real" object
+ delete m_data;
+}
+
+
+// redirection to WriteOutputFile() of "real" object --------------------------
+//
+int OutputData3D::WriteOutputFile()
+{
+ return m_data ? m_data->WriteOutputFile() : FALSE;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/OutputData3D.h b/tool_src/BspLib/OutputData3D.h
new file mode 100644
index 0000000..2a61249
--- /dev/null
+++ b/tool_src/BspLib/OutputData3D.h
@@ -0,0 +1,44 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: OutputData3D.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _OUTPUTDATA3D_H_
+#define _OUTPUTDATA3D_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObjectList.h"
+#include "IOData3D.h"
+#include "InputData3D.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// generic output class for 3-D data ------------------------------------------
+//
+class OutputData3D : public IOData3D {
+
+public:
+ OutputData3D( BspObjectList objectlist, const char *filename, int format = BSP_FORMAT_1_1 );
+ OutputData3D( const InputData3D& inputdata, int format = BSP_FORMAT_1_1 );
+ virtual ~OutputData3D();
+
+ virtual int WriteOutputFile();
+
+protected:
+ int m_objectformat;
+
+private:
+ OutputData3D* m_data;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _OUTPUTDATA3D_H_
+
diff --git a/tool_src/BspLib/Plane.h b/tool_src/BspLib/Plane.h
new file mode 100644
index 0000000..3489d0a
--- /dev/null
+++ b/tool_src/BspLib/Plane.h
@@ -0,0 +1,146 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Plane.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _PLANE_H_
+#define _PLANE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// plane in 3-space; represented by normal and distance to origin -------------
+//
+class Plane {
+
+ enum {
+ NORMAL_VALID = 0x0001,
+ OFFSET_VALID = 0x0002,
+ PLANE_VALID = NORMAL_VALID | OFFSET_VALID,
+ };
+
+public:
+ Plane() : m_valid( 0 ) { }
+ Plane( const Vector3& pnormal );
+ Plane( const Vector3& pnormal, double poffset );
+ Plane( const Vertex3& v1, const Vertex3& v2, const Vertex3& v3 );
+ ~Plane() { }
+
+ int InitPlane( const Vertex3& v1, const Vertex3& v2, const Vertex3& v3 );
+ int CalcPlaneOffset( const Vertex3& vtx );
+
+ Vector3 getPlaneNormal() const { return m_normal; }
+ void setPlaneNormal( const Vector3& pnormal ) { m_normal = pnormal; }
+
+ double getPlaneOffset() const { return m_offset; }
+ void setPlaneOffset( double poffset ) { m_offset = poffset; }
+
+ int NormalValid() const { return ( ( m_valid & NORMAL_VALID ) == NORMAL_VALID ); }
+ int PlaneValid() const { return ( ( m_valid & PLANE_VALID ) == PLANE_VALID ); }
+
+ void ApplyScaleFactor( double sfac );
+ void EliminateDirectionality();
+
+ int PointContained( const Vertex3& point ) const;
+ int PointInPositiveHalfspace( const Vertex3& point ) const;
+ int PointInNegativeHalfspace( const Vertex3& point ) const;
+
+private:
+ Vector3 m_normal; // normal of plane
+ double m_offset; // distance of plane to origin
+ int m_valid; // flag if plane specification indeed valid
+};
+
+// construct a plane from plane normal only: leave offset invalid -------------
+inline Plane::Plane( const Vector3& pnormal )
+{
+ m_normal = pnormal;
+ m_offset = 0.0;
+ m_valid = NORMAL_VALID;
+}
+
+// construct a plane from plane normal and distance to origin -----------------
+inline Plane::Plane( const Vector3& pnormal, double poffset )
+{
+ m_normal = pnormal;
+ m_offset = poffset;
+ m_valid = PLANE_VALID;
+}
+
+// construct a plane from three vertices (affine combination) -----------------
+inline Plane::Plane( const Vertex3& v1, const Vertex3& v2, const Vertex3& v3 )
+{
+ // normal is calculated so that the three vertices comprise a
+ // triangle with the front face in clockwise order
+ m_normal.CrossProduct( v3 - v1, v2 - v1 );
+
+ // m_valid will be set to 0 if the three vertices are collinear
+ m_valid = m_normal.Normalize() ? PLANE_VALID : 0;
+
+ // compute offset via dot product
+ m_offset = m_normal.DotProduct( v1 );
+}
+
+// init plane from three points (after construction!) -------------------------
+inline int Plane::InitPlane( const Vertex3& v1, const Vertex3& v2, const Vertex3& v3 )
+{
+ *this = Plane( v1, v2, v3 );
+ return m_valid;
+}
+
+// calculate plane's distance to origin using already valid normal ------------
+inline int Plane::CalcPlaneOffset( const Vertex3& vtx )
+{
+ // compute offset via dot product
+ m_offset = m_normal.DotProduct( vtx );
+ return ( m_valid |= OFFSET_VALID );
+}
+
+// apply scale factor to plane's distance to origin ---------------------------
+inline void Plane::ApplyScaleFactor( double sfac )
+{
+ // this will be needed if an object containing
+ // explicit plane information is scaled.
+ m_offset *= sfac;
+}
+
+// eliminate frontfacing/backfacing property; force positive offset -----------
+inline void Plane::EliminateDirectionality()
+{
+ if ( m_offset < 0.0 ) {
+ m_normal *= -1.0;
+ m_offset = -m_offset;
+ }
+}
+
+// determine if a point is contained in the plane -----------------------------
+inline int Plane::PointContained( const Vertex3& point ) const
+{
+ return ( fabs( m_normal.DotProduct( point ) - m_offset ) < EPS_POINT_ON_PLANE );
+}
+
+// determine if a point is contained in the positive open halfspace -----------
+inline int Plane::PointInPositiveHalfspace( const Vertex3& point ) const
+{
+ return ( m_normal.DotProduct( point ) - m_offset >= EPS_POINT_ON_PLANE );
+}
+
+// determine if a point is contained in the negative open halfspace -----------
+inline int Plane::PointInNegativeHalfspace( const Vertex3& point ) const
+{
+ return ( m_normal.DotProduct( point ) - m_offset <= -EPS_POINT_ON_PLANE );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _PLANE_H_
+
diff --git a/tool_src/BspLib/Polygon.cpp b/tool_src/BspLib/Polygon.cpp
new file mode 100644
index 0000000..543a1f7
--- /dev/null
+++ b/tool_src/BspLib/Polygon.cpp
@@ -0,0 +1,1042 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Polygon.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "BspObject.h"
+#include "Polygon.h"
+#include "BoundingBox.h"
+#include "BSPNode.h"
+#include "BspTool.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct a Polygon --------------------------------------------------------
+//
+Polygon::Polygon( BspObject *bobj, int pno, int fno, Polygon *next, int num )
+{
+ baseobject = bobj;
+ polygonno = pno;
+ faceno = fno;
+ nextpolygon = next;
+ numpolygons = num;
+ numvertindxs = 0;
+ vertindxs = NULL;
+ vindxinsertpos = NULL;
+}
+
+
+// get vertexlist of object polygon belongs to --------------------------------
+//
+VertexChunk& Polygon::getVertexList()
+{
+ CHECK_DEREFERENCING(
+ if ( baseobject == NULL )
+ Error();
+ );
+ return baseobject->getVertexList();
+}
+
+
+// get facelist of object polygon belongs to ----------------------------------
+//
+FaceChunk& Polygon::getFaceList()
+{
+ CHECK_DEREFERENCING(
+ if ( baseobject == NULL )
+ Error();
+ );
+ return baseobject->getFaceList();
+}
+
+
+// create new polygon and prepend it to list (append list to new polygon) -----
+//
+Polygon *Polygon::NewPolygon()
+{
+ //CAVEAT:
+ // the automatical assignment of polygon and face number
+ // must be used judiciously! it's very easy to get the
+ // numbering wrong. also, a single polygon cannot be
+ // used as "polygon-factory" since it will always assign
+ // the same numbers to the new polygons, based on its own.
+
+ //NOTE:
+ // normally, this function should only be used like this:
+ // poly = poly->NewPolygon();
+
+ // automatically assign sequential polygon- and face-number
+ return new Polygon( baseobject, numpolygons, numpolygons, this, numpolygons + 1 );
+}
+
+
+// prepend existing polygon to list (polygon- and face id are not changed!) ---
+//
+Polygon *Polygon::InsertPolygon( Polygon *poly )
+{
+ poly->nextpolygon = this;
+ poly->numpolygons = numpolygons + 1;
+ poly->baseobject = baseobject;
+ return poly;
+}
+
+
+// delete head of polygon list; return rest of list ---------------------------
+//
+Polygon *Polygon::DeleteHead()
+{
+ Polygon *temp = nextpolygon;
+ nextpolygon = NULL;
+ delete this;
+ //CAVEAT:
+ // this can create problems if function not used correctly!
+ // INVOKE ONLY LIKE THIS: poly = poly->DeleteHead();
+ // otherwise a dangling pointer will be created!
+ // THIS FUNCTION MAY ALSO NEVER BE INVOKED ON STATICALLY
+ // ALLOCATED POLYGONS!!
+ return temp;
+}
+
+
+// find polygon with specific id ----------------------------------------------
+//
+Polygon *Polygon::FindPolygon( int id )
+{
+ // scan entire list and compare ids
+ for ( Polygon *scanpo = this; scanpo; scanpo = scanpo->getNext() ) {
+ if ( scanpo->getId() == id )
+ return scanpo;
+ }
+ // no polygon with this id found
+ return NULL;
+}
+
+
+// sum up vertex numbers for all polygons of list -----------------------------
+//
+int Polygon::SumVertexNumsEntireList()
+{
+ // scan entire list and compare ids
+ int count = 0;
+ for ( Polygon *scanpo = this; scanpo; scanpo = scanpo->getNext() )
+ count += scanpo->getNumVertices();
+ return count;
+}
+
+
+// correct relative values to refer to new base -------------------------------
+//
+void Polygon::CorrectBase( BspObject *newbaseobj, int vertexindxbase, int faceidbase, int polygonidbase )
+{
+ baseobject = newbaseobj;
+ faceno += faceidbase;
+ polygonno += polygonidbase;
+ // correct all vertex indexes by just adding offset value
+ for ( VIndx *vertlist = vertindxs; vertlist; vertlist = vertlist->getNext() )
+ vertlist->setIndx( vertlist->getIndx() + vertexindxbase );
+}
+
+
+// correct relative values to refer to new base using vertex index map --------
+//
+void Polygon::CorrectBaseByTable( BspObject *newbaseobj, int *vtxindxmap, int faceidbase, int polygonidbase )
+{
+ baseobject = newbaseobj;
+ faceno += faceidbase;
+ polygonno += polygonidbase;
+ // correct all vertex indexes using mapping table
+ for ( VIndx *vertlist = vertindxs; vertlist; vertlist = vertlist->getNext() )
+ vertlist->setIndx( vtxindxmap[ vertlist->getIndx() ] );
+}
+
+
+// write list of vertices to text-file ----------------------------------------
+//
+void Polygon::FillVertexIndexArray( dword *arr ) const
+{
+ // scan list of vertex indexes and write them into the int array
+ for ( VIndx *vertlist = vertindxs; vertlist; vertlist = vertlist->getNext() )
+ *arr++ = vertlist->getIndx();
+}
+
+
+// write list of vertices to text-file ----------------------------------------
+//
+void Polygon::WriteVertexList( FILE *fp, int cr ) const
+{
+ // scan list of vertex indexes and write them to text file
+ for ( VIndx *vertlist = vertindxs; vertlist; vertlist = vertlist->getNext() )
+ fprintf( fp, vertlist->getNext() ? "%d, " : "%d", vertlist->getIndx() + 1 );
+ if ( cr )
+ fprintf( fp, "\n" );
+}
+
+
+// write list of polygon numbers to text-file (reverse ordering) --------------
+//
+void Polygon::WritePolyList( FILE *fp ) const
+{
+ // recurse to achieve reverse ordering
+ if ( nextpolygon )
+ nextpolygon->WritePolyList( fp );
+
+ fprintf( fp, "%d, ", getId() + 1 );
+}
+
+
+// add new VIndx for polygon at head of vertindxs -----------------------------
+//
+void Polygon::PrependNewVIndx( int indx )
+{
+ // prepend new VIndx
+ VIndx *oldhead = vertindxs;
+ vertindxs = new VIndx( indx, oldhead );
+ // remember last node in list
+ if ( vindxinsertpos == NULL )
+ vindxinsertpos = vertindxs;
+ // update number of vertex indexes
+ numvertindxs++;
+}
+
+
+// add new VIndx for polygon at tail of vertindxs -----------------------------
+//
+void Polygon::AppendNewVIndx( int indx )
+{
+ // append new VIndx
+ if ( vindxinsertpos != NULL ) {
+ vindxinsertpos->setNext( new VIndx( indx ) );
+ vindxinsertpos = vindxinsertpos->getNext();
+ } else {
+ vertindxs = new VIndx( indx );
+ vindxinsertpos = vertindxs;
+ }
+ // update number of vertex indexes
+ numvertindxs++;
+}
+
+
+// append existing VIndx at tail of vertindxs ---------------------------------
+//
+void Polygon::AppendVIndx( VIndx *vindx )
+{
+ // append passed in VIndx
+ if ( vindxinsertpos ) {
+ vindxinsertpos->setNext( vindx );
+ } else {
+ vertindxs = vindx;
+ }
+
+ vindxinsertpos = vindx;
+ //CAVEAT:
+ // if passed in VIndx is the head of a list
+ // that list is unlinked when appending!
+ vindx->setNext( NULL );
+ // update number of vertex indexes
+ numvertindxs++;
+}
+
+
+// unlink last node in list of vertex indexes ---------------------------------
+//
+VIndx *Polygon::UnlinkLastVIndx()
+{
+ VIndx *vlist = vertindxs;
+ if ( vlist ) {
+ numvertindxs--;
+ if ( vlist->getNext() ) {
+ for ( ; vlist->getNext()->getNext(); vlist = vlist->getNext() ) ;
+ vindxinsertpos = vlist;
+ VIndx *node = vlist->getNext();
+ vlist->setNext( NULL );
+ return node;
+ } else {
+ // return one and only node in list
+ vindxinsertpos = NULL;
+ vertindxs = NULL;
+ return vlist;
+ }
+ } else {
+ // list was already empty
+ return NULL;
+ }
+}
+
+
+// calculate bounding box encompassing all polygons in list -------------------
+//
+void Polygon::CalcBoundingBox( BoundingBox* &boundingbox )
+{
+ VertexChunk& vtxlist = getVertexList();
+ VIndx *polyvertlist = getVList();
+
+ Vertex3 minvertex = vtxlist[ polyvertlist->getIndx() ];
+ Vertex3 maxvertex = vtxlist[ polyvertlist->getIndx() ];
+ polyvertlist = polyvertlist->getNext();
+
+ for ( Polygon *curpoly = this; ; ) {
+
+ for ( ; polyvertlist; polyvertlist = polyvertlist->getNext() ) {
+ Vertex3& testvertex = vtxlist[ polyvertlist->getIndx() ];
+
+ if ( testvertex.getX() < minvertex.getX() )
+ minvertex.setX( testvertex.getX() );
+ if ( testvertex.getY() < minvertex.getY() )
+ minvertex.setY( testvertex.getY() );
+ if ( testvertex.getZ() < minvertex.getZ() )
+ minvertex.setZ( testvertex.getZ() );
+
+ if ( testvertex.getX() > maxvertex.getX() )
+ maxvertex.setX( testvertex.getX() );
+ if ( testvertex.getY() > maxvertex.getY() )
+ maxvertex.setY( testvertex.getY() );
+ if ( testvertex.getZ() > maxvertex.getZ() )
+ maxvertex.setZ( testvertex.getZ() );
+ }
+
+ if ( ( curpoly = curpoly->getNext() ) != NULL )
+ polyvertlist = curpoly->getVList();
+ else
+ break;
+ }
+
+ //CAVEAT:
+ // boundingbox MUST NOT be initialized, since it
+ // is overwritten without deletion!
+ boundingbox = new BoundingBox( minvertex, maxvertex );
+}
+
+
+// check which class with respect to the splitter a given polygon belongs to --
+//
+int Polygon::CheckIntersection( Polygon *testpoly )
+{
+ VertexChunk& vtxlist = getVertexList();
+ Plane splitterplane = getPlane();
+
+ int numneg = 0, numpos = 0, numzero = 0;
+
+ // classify all vertices of polygon with respect to splitting plane
+ VIndx *polyvertlist = testpoly->getVList();
+ for ( ; polyvertlist; polyvertlist = polyvertlist->getNext() ) {
+ Vertex3 curvertex = vtxlist[ polyvertlist->getIndx() ];
+
+ if ( splitterplane.PointInPositiveHalfspace( curvertex ) )
+ numpos++;
+ else if ( splitterplane.PointInNegativeHalfspace( curvertex ) )
+ numneg++;
+ else
+ numzero++;
+ }
+
+ // determine polygon's classification from vertex classifications
+ if ( ( numneg == 0 ) && ( numpos == 0 ) )
+ return POLY_IN_SAME_PLANE;
+ else if ( numneg == 0 )
+ return POLY_IN_FRONT_SUBSPACE;
+ else if ( numpos == 0 )
+ return POLY_IN_BACK_SUBSPACE;
+ else
+ return POLY_STRADDLES_SPLITTER;
+}
+
+
+// check which halfspace another polygon's normal's tip lies in ---------------
+//
+int Polygon::NormalDirectionSimilar( Polygon *testpoly )
+{
+ // calculate position of normal's tip
+ Vertex3 normalstip = testpoly->getFirstVertex() + testpoly->getPlaneNormal();
+
+ // check position of tip with respect to this polygon's plane
+ return !getPlane().PointInNegativeHalfspace( normalstip );
+}
+
+
+// split polygon straddling two subspaces -------------------------------------
+//
+void Polygon::SplitPolygon( Polygon *poly, Polygon* &frontsubspace, Polygon* &backsubspace )
+{
+ VertexChunk& vtxlist = getVertexList();
+ FaceChunk& facelist = getFaceList();
+
+ if ( display_messages & MESSAGE_SPLITTING_POLYGON ) {
+ sprintf( str_scratchpad, "--- Splitting polygon %d\n", poly->getId() + 1 );
+ InfoMessage( str_scratchpad );
+ }
+
+ // create the two new polygons: one for each subspace.
+ // the original polygon (this) will not be deleted by this function.
+ Polygon *frontpoly = new Polygon( baseobject,
+ poly->getId(),
+ poly->getFaceId(),
+ frontsubspace );
+ Polygon *backpoly = new Polygon( baseobject,
+ poly->getId(),
+ poly->getFaceId(),
+ backsubspace );
+
+ // fetch normal vector and arbitrary point on splitter plane
+ Vector3 splitternormal = getPlaneNormal();
+ Vertex3 splittervertex = getFirstVertex();
+
+ // init pointer to vertex-list of source polygon
+ VIndx *polyvertlist = poly->getVList();
+
+ // check location of first vertex and set starting subspace accordingly
+ Vector3 directionvec( splittervertex, poly->getFirstVertex() );
+ if ( normalize_vectors )
+ directionvec.Normalize();
+ double scalprod( splitternormal.DotProduct( directionvec ) );
+
+ // check if first vertex lies in splitter plane
+ if ( fabs( scalprod ) < EPS_SCALAR ) {
+
+ if ( display_messages & MESSAGE_STARTVERTEX_IN_SPLITTER_PLANE ) {
+ sprintf( str_scratchpad, "Startvertex in splitter-plane: %d\n",
+ polyvertlist->getIndx() + 1 );
+ InfoMessage( str_scratchpad );
+ }
+ VIndx *scan = NULL;
+ // scan vertex list for vertex not contained in splitter plane
+ for ( scan = polyvertlist->getNext(); scan; scan = scan->getNext() ) {
+ directionvec.CreateDirVec( splittervertex, vtxlist[ scan->getIndx() ] );
+ if ( normalize_vectors )
+ directionvec.Normalize();
+ // set scalprod such that the start-subspace is opposite
+ // the first non-contained vertex's subspace
+ scalprod = -splitternormal.DotProduct( directionvec );
+ // exit loop if non-contained vertex found
+ if ( fabs( scalprod ) >= EPS_SCALAR )
+ break;
+ }
+
+ if ( display_messages & MESSAGE_STARTVERTEX_IN_SPLITTER_PLANE ) {
+ if ( scan == NULL ) {
+ sprintf( str_scratchpad, "WARNING: all vertices contained in splitter-plane!\n" );
+ } else {
+ sprintf( str_scratchpad, "Using vertex %d for halfspace classification.\n",
+ scan->getIndx() + 1 );
+ }
+ InfoMessage( str_scratchpad );
+ }
+ }
+/*
+ // check if polygon to split is non-convex
+ if ( [non-convex polygon] ) {
+ ErrorMessage( "***ERROR*** Non-convex polygon encountered while splitting." );
+ HandleCriticalError();
+ }
+*/
+ // select subspace to start in
+ int cursubspace = ( scalprod > 0.0 ) ? FRONT_SUBSPACE : BACK_SUBSPACE;
+
+ // split polygon into two polygons; one for each subspace ---------------
+ int twas1 = 0;
+ for ( ; polyvertlist; polyvertlist = polyvertlist->getNext() ) {
+
+ // copy current vertex from source polygon to its respective subspace
+ if ( cursubspace == FRONT_SUBSPACE )
+ frontpoly->AppendNewVIndx( polyvertlist->getIndx() );
+ else
+ backpoly->AppendNewVIndx( polyvertlist->getIndx() );
+
+ // check intersection of splitter plane with next lineseg -----
+ int nextvertex = polyvertlist->getNext() ?
+ polyvertlist->getNext()->getIndx() : poly->getVList()->getIndx();
+
+ // denominator is length of projection of lineseg onto plane normal
+ Vector3 linevec( vtxlist[ polyvertlist->getIndx() ], vtxlist[ nextvertex ] );
+ double denominator = splitternormal.DotProduct( linevec );
+
+ // numerator is distance from splittervertex to startvertex of lineseg
+ Vector3 directionvec( splittervertex, vtxlist[ polyvertlist->getIndx() ] );
+ double numerator = splitternormal.DotProduct( directionvec );
+
+ // if lineseg isn't parallel to splitter plane, check for intersection
+ if ( fabs( denominator ) >= EPS_DENOM_ZERO ) {
+
+ double t = - numerator / denominator;
+ if ( twas1 || ( fabs( t ) < EPS_POINT_ON_LINESEG ) ) {
+
+ if ( display_messages & MESSAGE_VERTEX_IN_SPLITTER_PLANE ) {
+ sprintf( str_scratchpad, "Vertex in splitter-plane! (%d)\n", polyvertlist->getIndx() + 1 );
+ InfoMessage( str_scratchpad );
+ }
+
+ // reset flag
+ twas1 = 0;
+
+ // switch subspace and insert same vertex again
+ cursubspace = -cursubspace;
+ if ( cursubspace == FRONT_SUBSPACE )
+ frontpoly->AppendNewVIndx( polyvertlist->getIndx() );
+ else
+ backpoly->AppendNewVIndx( polyvertlist->getIndx() );
+
+ // check if next vertex is contained in the other subspace
+ Vector3 directionvec( splittervertex, vtxlist[ nextvertex ] );
+ if ( normalize_vectors )
+ directionvec.Normalize();
+ double scalprod( splitternormal.DotProduct( directionvec ) );
+ if ( ( ( scalprod < 0.0 ) && ( cursubspace == FRONT_SUBSPACE ) ) ||
+ ( ( scalprod > 0.0 ) && ( cursubspace == BACK_SUBSPACE ) ) ) {
+ // switch back again
+ cursubspace = -cursubspace;
+ if ( display_messages & MESSAGE_VERTEX_IN_SPLITTER_PLANE ) {
+ sprintf( str_scratchpad, "Vertex alone in %s halfspace!\n",
+ ( cursubspace == BACK_SUBSPACE ) ? "front" : "back" );
+ InfoMessage( str_scratchpad );
+ }
+ }
+
+ //NOTE:
+ // the above check is necessary to avoid problems with polygons actually
+ // entirely contained in a single subspace but nevertheless classified as
+ // straddling. in this case the implicit subspace-switching for t=0 vertices
+ // would cause these vertices to be inserted into the wrong subspace!
+
+ } else if ( ( t >= EPS_POINT_ON_LINESEG ) && ( t <= 1.0 - EPS_POINT_ON_LINESEG ) ) {
+
+ // insert intersection point into both subspaces and switch
+ cursubspace = -cursubspace;
+ Vertex3 newvertex( linevec * t + vtxlist[ polyvertlist->getIndx() ] );
+ int newvertindx = vtxlist.FindCloseVertex( newvertex );
+ if ( newvertindx == -1 ) {
+ newvertindx = vtxlist.AddVertex( newvertex );
+ if ( display_messages & MESSAGE_NEW_SPLITVERTEX ) {
+ sprintf( str_scratchpad, "Inserting new split-vertex (%d)\n", vtxlist.getNumElements() );
+ InfoMessage( str_scratchpad );
+ }
+ } else if ( display_messages & MESSAGE_REUSING_SPLITVERTEX ) {
+ sprintf( str_scratchpad, "Reusing split-vertex (%d)\n", newvertindx + 1 );
+ InfoMessage( str_scratchpad );
+ }
+
+ frontpoly->AppendNewVIndx( newvertindx );
+ backpoly->AppendNewVIndx( newvertindx );
+
+ } else if ( fabs( t - 1.0 ) < EPS_POINT_ON_LINESEG ) {
+
+ // set flag
+ twas1 = 1;
+
+ //NOTE:
+ // this flag is necessary to avoid numerical problems when
+ // a vertex is classified as t=1 for one edge but is not
+ // classified as t=0 for the next edge.
+
+ // if this is not the last vertex it will be inserted
+ // during the next iteration. if not, the insertion
+ // must be done here, otherwise a vertex will be missing
+ // for the current polygon!
+ if ( polyvertlist->getNext() == NULL ) {
+ // determine vertex's subspace
+ Polygon *testpoly = ( cursubspace == FRONT_SUBSPACE ) ? frontpoly : backpoly;
+ // check if not already inserted as first vertex
+ if ( ( testpoly->getVList() != NULL ) &&
+ ( testpoly->getVList()->getIndx() == nextvertex ) )
+ continue;
+ // insert last vertex into its subspace
+ testpoly->AppendNewVIndx( nextvertex );
+ }
+ }
+
+ } else if ( polyvertlist->getNext() == NULL ) {
+
+ // determine last vertex's subspace
+ Polygon *testpoly = ( cursubspace == FRONT_SUBSPACE ) ? frontpoly : backpoly;
+ // check if not already inserted as first vertex
+ if ( ( testpoly->getVList() != NULL ) &&
+ ( testpoly->getVList()->getIndx() == nextvertex ) )
+ continue;
+ // insert last vertex into its subspace
+ testpoly->AppendNewVIndx( nextvertex );
+ }
+ }
+
+ // check generated polygons for degeneration
+ if ( frontpoly->HasArea() ) {
+ // insert front poly into front subspace
+ frontsubspace = frontpoly;
+ // check back poly
+ if ( backpoly->HasArea() ) {
+ // insert back poly into back subspace
+ backsubspace = backpoly;
+ // set new id in sequence
+ backpoly->setId( baseobject->getNumPolygons() );
+ // this poly has not been counted yet
+ baseobject->numpolygons++;
+ } else {
+ // remove degenerated back poly
+ backpoly->setNext( NULL );
+ delete backpoly;
+ if ( display_messages & MESSAGE_SPLITTING_POLYGON )
+ InfoMessage( "Split not carried out due to boundary case: polygon in front halfspace.\n" );
+ }
+ } else {
+ // remove degenerated front poly
+ frontpoly->setNext( NULL );
+ delete frontpoly;
+ if ( display_messages & MESSAGE_SPLITTING_POLYGON )
+ InfoMessage( "Split not carried out due to boundary case: polygon in back halfspace.\n" );
+ // check back poly
+ if ( backpoly->HasArea() ) {
+ // insert back poly into back subspace
+ backsubspace = backpoly;
+ } else {
+ // both polygons degenerated: should be impossible!
+ Error();
+ }
+ }
+}
+
+
+// partition list of polygons into two halfspaces (heavily recursive!) --------
+//
+BSPNode *Polygon::PartitionSpace()
+{
+ // display invocation message if flag set
+ if ( display_messages & MESSAGE_INVOCATION ) {
+ sprintf( str_scratchpad, "PartitionSpace() called: #%d polygon %d\n",
+ partition_callcount, getId() + 1 );
+ InfoMessage( str_scratchpad );
+ partition_callcount++;
+ }
+
+ // only one polygon in this halfspace?
+ if ( nextpolygon == NULL ) {
+ if ( display_messages & MESSAGE_INVOCATION ) {
+ sprintf( str_scratchpad, "Leaf: polygon %d\n", getId() + 1 );
+ InfoMessage( str_scratchpad );
+ }
+ return new BSPNode( NULL, NULL, this, NULL );
+ }
+
+ // used after recursive calls: has to be automatic!!
+ Polygon *splitter = this;
+
+ // take first polygon in list without testing?
+ if ( splitter_crit == SPLITTERCRIT_FIRST_POLY )
+ goto splitter_selected;
+
+ // find best candidate for splitter -----------------------------
+ static int bestnumsplitted;
+ static int bestnumcontained;
+ bestnumsplitted = INT_MAX;
+ bestnumcontained = 0;
+
+ static int samplecount;
+ samplecount = 0;
+
+ static Polygon *currentsplitter;
+ static Polygon *precpolygon;
+ static Polygon *splitterpred;
+ currentsplitter = this;
+ precpolygon = NULL;
+ splitterpred = NULL;
+
+ // walk polygon list trying to find appropriate splitter
+ for ( ; currentsplitter; precpolygon = currentsplitter, currentsplitter = currentsplitter->getNext() ) {
+
+ if ( splitter_crit == SPLITTERCRIT_RANDOM_SAMPLE ) {
+ //TODO: don't use rtl rand() as pseudo random number generator
+ //NOTE: assumes that RAND_MAX is at least 10000
+ if ( ( rand() % 10000 ) > test_probability )
+ continue;
+ }
+
+ static int numsplitted;
+ static int numcontained;
+ numsplitted = 0;
+ numcontained = 0;
+
+ // determine number of polygons splitted and contained by *currentsplitter, respectively
+ static Polygon *scanpo;
+ for ( scanpo = this; scanpo; scanpo = scanpo->getNext() ) {
+ if ( scanpo != currentsplitter ) {
+ switch ( currentsplitter->CheckIntersection( scanpo ) ) {
+ case POLY_STRADDLES_SPLITTER:
+ numsplitted++;
+ break;
+ case POLY_IN_SAME_PLANE:
+ numcontained++;
+ break;
+ default:
+ // *currentsplitter neither splits nor contains *scanpo
+ break;
+ }
+ }
+ }
+
+ if ( numsplitted == 0 ) {
+ // if nothing splitted at all, skip all other tests
+ splitter = currentsplitter;
+ splitterpred = precpolygon;
+ break;
+ } else if ( numsplitted < bestnumsplitted ) {
+ splitter = currentsplitter;
+ splitterpred = precpolygon;
+ bestnumsplitted = numsplitted;
+ bestnumcontained = numcontained;
+ } else if ( ( numsplitted == bestnumsplitted ) && ( numcontained > bestnumcontained ) ) {
+ splitter = currentsplitter;
+ splitterpred = precpolygon;
+ bestnumcontained = numcontained;
+ }
+
+ // test sample size for SPLITTERCRIT_SAMPLE_FIRST_N and SPLITTERCRIT_RANDOM_SAMPLE
+ if ( splitter_crit & SPLITTERCRITMASK_SAMPLESIZ ) {
+ // desired sample size already reached?
+ if ( ++samplecount >= sample_size )
+ break;
+ }
+ }
+
+splitter_selected:
+
+ // build polygon list without splitter
+ static Polygon *polylist;
+ polylist = this;
+ if ( splitter == polylist ) {
+ polylist = splitter->getNext();
+ } else {
+ splitterpred->setNext( splitter->getNext() );
+ }
+
+ splitter->setNext( NULL ); // unlink splitter from rest of list
+ splitter->setNumPolygons( 1 ); // splitter contains only itself
+
+ // display splitter info
+ if ( display_messages & MESSAGE_INVOCATION ) {
+ sprintf( str_scratchpad, "Splitter: polygon %d\n", splitter->getId() + 1 );
+ InfoMessage( str_scratchpad );
+ }
+
+ // partition space; create subspace lists -----------------------
+ Polygon *frontsubspace = NULL;
+ Polygon *backsubspace = NULL;
+ Polygon *backlist = NULL; // list of backfacing polygons
+
+ static Polygon *containlist; // append position for contained polygons
+ containlist = splitter;
+ while ( polylist != NULL ) {
+
+ static Polygon *temppoly;
+ switch ( splitter->CheckIntersection( polylist ) ) {
+
+ // polygon completely contained in front-subspace
+ case POLY_IN_FRONT_SUBSPACE:
+ temppoly = polylist->getNext();
+ polylist->setNext( frontsubspace );
+ frontsubspace = polylist;
+ polylist = temppoly;
+ break;
+
+ // polygon completely contained in back-subspace
+ case POLY_IN_BACK_SUBSPACE:
+ temppoly = polylist->getNext();
+ polylist->setNext( backsubspace );
+ backsubspace = polylist;
+ polylist = temppoly;
+ break;
+
+ // polygon straddles plane of splitter
+ case POLY_STRADDLES_SPLITTER:
+ // split polygon and add split pieces to the front- and back-subspace, respectively
+ splitter->SplitPolygon( polylist, frontsubspace, backsubspace );
+ // delete split polygon
+ polylist = polylist->DeleteHead();
+ break;
+
+ // polygon lies in same plane as splitter
+ case POLY_IN_SAME_PLANE:
+ temppoly = polylist->getNext();
+ if ( splitter->NormalDirectionSimilar( polylist ) ) {
+ // insert frontfacing polygon into contained list (at tail)
+ containlist->setNext( polylist );
+ containlist = polylist;
+ containlist->setNext( NULL );
+ containlist->setNumPolygons( 1 );
+ //CAVEAT:
+ // numpolygons is only correct for first polygon in contained-list (splitter)!!
+ splitter->numpolygons++;
+ } else {
+ // insert backfacing polygon into backlist (at head)
+ polylist->setNext( backlist );
+ polylist->setNumPolygons( backlist ? backlist->getNumPolygons() + 1 : 1 );
+ backlist = polylist;
+ }
+ polylist = temppoly;
+ break;
+ }
+ }
+
+ // allocate new root; partition halfspaces recursively and return root
+ BSPNode *front = frontsubspace ? frontsubspace->PartitionSpace() : NULL;
+ BSPNode *back = backsubspace ? backsubspace->PartitionSpace() : NULL;
+ return new BSPNode( front, back, splitter, backlist );
+}
+
+
+// calculate plane normals for planes of all polygons -------------------------
+//
+void Polygon::CalcPlaneNormals()
+{
+ // scan entire polygon list
+ FaceChunk& facelist = getFaceList();
+ for ( Polygon *polyscan = this; polyscan; polyscan = polyscan->getNext() ) {
+ // calculate plane (and normal) if not valid yet
+ Face& curface = facelist[ polyscan->getFaceId() ];
+ if ( !curface.PlaneValid() )
+ curface.CalcPlane( polyscan->getFirstVertex(),
+ polyscan->getSecondVertex(),
+ polyscan->getThirdVertex() );
+ }
+}
+
+
+// check all edges for t-vertices and insert trace-vertices as appropriate ----
+//
+void Polygon::CheckEdges()
+{
+ //NOTE:
+ // this function is terribly slow, because for every polygon
+ // every single edge is checked whether it contains any vertices.
+ // thus, overall every edge is checked twice for containment
+ // of all vertices and no topological information is used at all!
+
+ VertexChunk& vtxlist = getVertexList();
+
+ // scan all polygons
+ for ( Polygon *poly = this; poly; poly = poly->getNext() ) {
+ // just to be sure
+ int numvtxs = vtxlist.getNumElements();
+ if ( numvtxs < 3 )
+ continue;
+ // create vertex mask array
+ char *vmask = new char[ numvtxs ];
+ memset( vmask, 0, sizeof( char ) * numvtxs );
+ // scan all edges: init mask
+ VIndx *polyvertlist = poly->getVList();
+ for ( ; polyvertlist; polyvertlist = polyvertlist->getNext() )
+ vmask[ polyvertlist->getIndx() ] = 1;
+ // scan all edges: check t-junctions
+ polyvertlist = poly->getVList();
+ for ( ; polyvertlist; polyvertlist = polyvertlist->getNext() ) {
+ // determine next vertex with wrap-around
+ int nextvertex = polyvertlist->getNext() ?
+ polyvertlist->getNext()->getIndx() : poly->getVList()->getIndx();
+ // create directed edge
+ Vector3 linevec( vtxlist[ polyvertlist->getIndx() ], vtxlist[ nextvertex ] );
+ // check edge against all vertices not masked out
+ for ( int i = 0; i < numvtxs; i++ )
+ if ( vmask[ i ] == 0 ) {
+ LineSeg3 lineseg( vtxlist[ polyvertlist->getIndx() ], linevec );
+ if ( lineseg.PointOnLineSeg( vtxlist[ i ] ) ) {
+
+ // create new vertex-index
+ VIndx *tempvindx = new VIndx( i, polyvertlist->getNext() );
+ polyvertlist->setNext( tempvindx );
+ if ( tempvindx->getNext() == NULL ) {
+
+ //NOTE:
+ // if tracevertex is inserted into last edge, AppendNewVIndx() and AppendVIndx()
+ // wouldn't work anymore if the insertposition in the polygon isn't
+ // updated correctly; normally this isn't done anyway, though
+
+ vindxinsertpos = tempvindx;
+ }
+
+ // new endpoint for lineseg to check
+ nextvertex = i;
+ vmask[ i ] = 1;
+ linevec.CreateDirVec( vtxlist[ polyvertlist->getIndx() ], vtxlist[ nextvertex ] );
+ baseobject->numtracevertices++;
+
+ if ( display_messages & MESSAGE_TRACEVERTEX_INSERTED ) {
+ sprintf( str_scratchpad, "Trace vertex inserted: polygon %d, vertex %d\n",
+ poly->getId() + 1, i + 1 );
+ InfoMessage( str_scratchpad );
+ }
+ }
+ }
+ }
+ // remove mask array
+ delete vmask;
+ }
+}
+
+
+// split polygons with vertices not contained in the same plane ---------------
+//
+Polygon *Polygon::CheckPlanesAndMappings()
+{
+ //NOTE:
+ // for historical reasons this function checks only quadrilaterals
+ // for planarity! i.e., if a polygon has more than 4 vertices no
+ // check is done at all whether all vertices are contained in the
+ // same plane. quadrilaterals, however, are checked and split into
+ // two triangles if nonplanar.
+ // explicit triangulation of quadrilaterals can be forced by using
+ // the static Polygon::triangulate_all flag.
+
+ // fetch vertex and face lists
+ VertexChunk& vtxlist = getVertexList();
+ FaceChunk& facelist = getFaceList();
+
+ if ( display_messages & MESSAGE_CHECKING_POLYGON_PLANES )
+ InfoMessage( "\nChecking polygon planes and mappings...\n" );
+
+ // scan entire polygon list
+ Polygon *polylist = this;
+ for ( Polygon *polyscan = polylist; polyscan; polyscan = polyscan->getNext() ) {
+
+ Face& curface = facelist[ polyscan->getFaceId() ];
+ int vertindx1 = polyscan->getFirstVertexIndx();
+ int vertindx2 = polyscan->getSecondVertexIndx();
+ int vertindx3 = polyscan->getThirdVertexIndx();
+
+ // calculate face plane/normal if not already done
+ if ( !curface.PlaneValid() )
+ curface.CalcPlane( vtxlist[ vertindx1 ], vtxlist[ vertindx2 ], vtxlist[ vertindx3 ] );
+
+ // convert correspondences to face mapping if not already done
+ if ( curface.FaceTexMapped() && !curface.MappingAttached() ) {
+ // calc correspondence number
+ int corrno = 0;
+ for ( int i = 0; i < polyscan->getFaceId(); i++ )
+ if ( facelist[ i ].FaceTexMapped() )
+ corrno++;
+ // set projective space coordinates
+ curface.MapXY( 0 ).InitFromVertex3( vtxlist[ vertindx1 ] );
+ curface.MapXY( 1 ).InitFromVertex3( vtxlist[ vertindx2 ] );
+ curface.MapXY( 2 ).InitFromVertex3( vtxlist[ vertindx3 ] );
+ // set (u,v)-space coordinates
+ Vertex2 corrpoint;
+ corrpoint = baseobject->mappinglist[ corrno ].FetchMapPoint( vertindx1 );
+ curface.MapUV( 0 ) = corrpoint;
+ corrpoint = baseobject->mappinglist[ corrno ].FetchMapPoint( vertindx2 );
+ curface.MapUV( 1 ) = corrpoint;
+ corrpoint = baseobject->mappinglist[ corrno ].FetchMapPoint( vertindx3 );
+ curface.MapUV( 2 ) = corrpoint;
+ }
+
+ // check fourth vertex if face is quadrilateral
+ if ( polyscan->getNumVertices() == 4 ) {
+
+ VIndx *vindxscan = polyscan->getVList()->getNext()->getNext(); // pointer to third VIndx
+ int testvertindx = vindxscan->getNext()->getIndx(); // fourth vertindx
+ if ( !curface.getPlane().PointContained( vtxlist[ testvertindx ] ) || triangulate_all ) {
+
+ // split quadrilateral into triangles
+ polylist = polylist->NewPolygon(); // create second triangle
+ polylist->AppendNewVIndx( vertindx3 ); // append VIndx for third vertex
+ polylist->AppendVIndx( polyscan->UnlinkLastVIndx() ); // append existing VIndx for fourth vertex
+ polylist->AppendNewVIndx( vertindx1 ); // append VIndx for first vertex
+
+ if ( display_messages & MESSAGE_SPLITTING_QUADRILATERAL ) {
+ sprintf( str_scratchpad, "Splitting quadrilateral: polygon %d\n",
+ polyscan->getId() + 1 );
+ InfoMessage( str_scratchpad );
+ sprintf( str_scratchpad, "-->Creating new triangle: polygon %d\n",
+ polylist->getId() + 1 );
+ InfoMessage( str_scratchpad );
+ }
+ // update count of split quadrilaterals
+ baseobject->numsplitquadrilaterals++;
+ // create new face
+ int newfaceno = facelist.AddElement( curface );
+ Face& newface = facelist[ newfaceno ];
+ // update face id of new polygon
+ polylist->setFaceId( newfaceno );
+ // fetch first three vertices
+ vertindx1 = polylist->getFirstVertexIndx();
+ vertindx2 = polylist->getSecondVertexIndx();
+ vertindx3 = polylist->getThirdVertexIndx();
+ // calculate face normal
+ newface.CalcPlane( vtxlist[ vertindx1 ], vtxlist[ vertindx2 ], vtxlist[ vertindx3 ] );
+ // transfer mapping into face
+ if ( curface.FaceTexMapped() ) {
+ // calc correspondence number
+ int corrno = 0;
+ for ( int i = 0; i < polyscan->getFaceId(); i++ )
+ if( facelist[ i ].FaceTexMapped() )
+ corrno++;
+ // set projective space coordinates
+ newface.MapXY( 0 ).InitFromVertex3( vtxlist[ vertindx1 ] );
+ newface.MapXY( 1 ).InitFromVertex3( vtxlist[ vertindx2 ] );
+ newface.MapXY( 2 ).InitFromVertex3( vtxlist[ vertindx3 ] );
+ // set (u,v)-space coordinates
+ Vertex2 corrpoint;
+ corrpoint = baseobject->mappinglist[ corrno ].FetchMapPoint( vertindx1 );
+ newface.MapUV( 0 ) = corrpoint;
+ corrpoint = baseobject->mappinglist[ corrno ].FetchMapPoint( vertindx2 );
+ newface.MapUV( 1 ) = corrpoint;
+ corrpoint = baseobject->mappinglist[ corrno ].FetchMapPoint( vertindx3 );
+ newface.MapUV( 2 ) = corrpoint;
+ }
+ }
+ }
+ }
+
+ return polylist;
+}
+
+
+// calculate probability with which to test a single polygon ------------------
+//
+int Polygon::CalcSplitterTestProbability()
+{
+ double numerator = sample_size;
+ double denominator = numpolygons;
+ double prob = ( denominator > 0.0 ) ? numerator / denominator : 1.0;
+ prob = ( prob < 1.0 ) ? prob * 10000.0 : 10000.0;
+ test_probability = (int) floor( prob + 0.5 );
+ if ( test_probability < 1 ) test_probability = 1;
+ return ( numpolygons > 0 );
+}
+
+
+// unspecified error encountered ----------------------------------------------
+//
+void Polygon::Error() const
+{
+ ErrorMessage( "\n***ERROR*** in object of class BspLib::Polygon." );
+ HandleCriticalError();
+}
+
+
+// splitter selection ---------------------------------------------------------
+//
+int Polygon::splitter_crit = Polygon::SPLITTERCRIT_SAMPLE_ALL;
+int Polygon::sample_size = 20;
+int Polygon::test_probability = 10000; // means 100.00%
+
+
+// static flags ---------------------------------------------------------------
+//
+int Polygon::triangulate_all = FALSE;
+int Polygon::normalize_vectors = FALSE;
+int Polygon::display_messages = Polygon::MESSAGEMASK_DISPLAY_ALL;
+
+
+// counter for invocations of PartitionSpace() --------------------------------
+//
+int Polygon::partition_callcount = 0;
+
+
+// string scratch pad ---------------------------------------------------------
+//
+char Polygon::str_scratchpad[ 256 ] = "";
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Polygon.h b/tool_src/BspLib/Polygon.h
new file mode 100644
index 0000000..d83de32
--- /dev/null
+++ b/tool_src/BspLib/Polygon.h
@@ -0,0 +1,280 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Polygon.h
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _POLYGON_H_
+#define _POLYGON_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Chunk.h"
+#include "Face.h"
+#include "Plane.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+class BoundingBox;
+
+
+// vertex index (element of vertex index list) --------------------------------
+//
+class VIndx {
+
+public:
+ VIndx( int indx = -1, VIndx *next = NULL ) { vertindx = indx; nextvertindx = next; }
+ ~VIndx() { delete nextvertindx; }
+
+ int getIndx() const { return vertindx; }
+ void setIndx( int indx ) { vertindx = indx; }
+
+ VIndx* getNext() const { return nextvertindx; }
+ void setNext( VIndx *next ) { nextvertindx = next; }
+
+private:
+ int vertindx; // -1 means end of list, regardless of nextvertindx
+ VIndx* nextvertindx; // pointer to next VIndx in singly linked list
+};
+
+
+class BSPNode;
+class BspObject;
+
+
+// single polygon (element of polygon list) -----------------------------------
+//
+class Polygon : public virtual SystemIO {
+
+ friend class PolygonListRep;
+
+ void Error() const;
+
+ // possible classifications of polygon with respect to splitting plane
+ enum {
+ POLY_IN_FRONT_SUBSPACE,
+ POLY_IN_BACK_SUBSPACE,
+ POLY_STRADDLES_SPLITTER,
+ POLY_IN_SAME_PLANE,
+ };
+
+ // frontsubspace/backsubspace identifiers
+ enum {
+ FRONT_SUBSPACE = 1,
+ BACK_SUBSPACE = -1
+ };
+
+public:
+
+ // splitter selection criteria
+ enum {
+ SPLITTERCRIT_FIRST_POLY = 0x0000, // always choose first polygon in list
+ SPLITTERCRIT_SAMPLE_FIRST_N = 0x0101, // test first n polygons in list
+ SPLITTERCRIT_SAMPLE_ALL = 0x0002, // test entire list and choose best
+ SPLITTERCRIT_RANDOM_SAMPLE = 0x0103, // sample n polygons randomly
+ SPLITTERCRITMASK_SAMPLESIZ = 0x0100, // flagmask if samplesize (n) needed
+ };
+
+ // message flags
+ enum {
+ MESSAGE_SPLITTING_POLYGON = 0x0001,
+ MESSAGE_STARTVERTEX_IN_SPLITTER_PLANE = 0x0002,
+ MESSAGE_VERTEX_IN_SPLITTER_PLANE = 0x0004,
+ MESSAGE_NEW_SPLITVERTEX = 0x0008,
+ MESSAGE_REUSING_SPLITVERTEX = 0x0010,
+ MESSAGE_TRACEVERTEX_INSERTED = 0x0020,
+ MESSAGE_SPLITTING_QUADRILATERAL = 0x0040,
+ MESSAGE_INVOCATION = 0x0080,
+ MESSAGE_CHECKING_POLYGON_PLANES = 0x0100,
+ MESSAGEMASK_DISPLAY_ALL = 0xffff
+ };
+
+public:
+ Polygon( BspObject *bobj, int pno = 0, int fno = 0, Polygon *next = NULL, int num = 1 );
+ ~Polygon() { delete vertindxs; delete nextpolygon; }
+
+ Polygon* NewPolygon(); // create new polygon with sequential id as head of list
+ Polygon* InsertPolygon( Polygon *poly ); // insert existing polygon as head of list
+ Polygon* DeleteHead(); // delete this, return rest of list (DANGEROUS!)
+ Polygon* FindPolygon( int id ); // return polygon in list having specified id
+ int SumVertexNumsEntireList(); // sum up vertex numbers for all polygons of list
+
+ void PrependNewVIndx( int indx ); // create new VIndx and prepend it to list (vertindxs)
+ void AppendNewVIndx( int indx = -1 ); // create new VIndx and append it to list (vertindxs)
+ void AppendVIndx( VIndx *vindx ); // append existing VIndx to list (vertindxs)
+ VIndx* UnlinkLastVIndx(); // return last VIndx in list after unlinking it
+
+ void CalcPlaneNormals(); // calc normals for all polygons in list
+ void CheckEdges(); // check edges for contained vertices (scans list!)
+ Polygon* CheckPlanesAndMappings(); // check planes and mappings of all polygons in list
+
+ // calculate bounding box encompassing all polygons in list
+ void CalcBoundingBox( BoundingBox* &boundingbox );
+
+ // classify polygon with respect to this polygon
+ int CheckIntersection( Polygon *testpoly );
+ // check if other polygon's normal is contained in this one's positive halfspace (predicate)
+ int NormalDirectionSimilar( Polygon *testpoly );
+ // split other polygon along this polygon; insert split pieces into their respective halfspaces
+ void SplitPolygon( Polygon *poly, Polygon* &frontsubspace, Polygon* &backsubspace );
+ // partition space encompassing entire polygon list; return created BSP tree's root
+ BSPNode* PartitionSpace();
+
+ // correct numberings (polygon-id, face-id, and vertex indexes) to new base
+ void CorrectBase( BspObject *newbaseobj, int vertexindxbase, int faceidbase, int polygonidbase );
+ void CorrectBaseByTable( BspObject *newbaseobj, int *vtxindxmap, int faceidbase, int polygonidbase );
+
+ int getId() const { return polygonno; }
+ void setId( int pno ) { polygonno = pno; }
+
+ int getFaceId() const { return faceno; }
+ void setFaceId( int fno ) { faceno = fno; }
+
+ int getNumPolygons() const { return numpolygons; }
+ void setNumPolygons( int len ) { numpolygons = len; }
+
+ Polygon* getNext() const { return nextpolygon; }
+ void setNext( Polygon *next ) { nextpolygon = next; }
+
+ int getNumVertices() const { return numvertindxs; }
+
+ VIndx* getVList() const { return vertindxs; }
+ BspObject* getBaseObject() const { return baseobject; }
+
+ VertexChunk& getVertexList();
+ FaceChunk& getFaceList();
+
+ int HasArea() const;
+
+ int getFirstVertexIndx() const;
+ int getSecondVertexIndx() const;
+ int getThirdVertexIndx() const;
+
+ Vertex3 getFirstVertex() const;
+ Vertex3 getSecondVertex() const;
+ Vertex3 getThirdVertex() const;
+
+ Plane getPlane() const { return ((Polygon *const)this)->getFaceList()[ faceno ].getPlane(); }
+ Vector3 getPlaneNormal() const { return ((Polygon *const)this)->getFaceList()[ faceno ].getPlaneNormal(); }
+
+ void FillVertexIndexArray( dword *arr ) const; // write list of vertices into array
+ void WriteVertexList( FILE *fp, int cr ) const; // write list of vertices to file
+ void WritePolyList( FILE *fp ) const; // write list of polygon ids to file
+
+ int CalcSplitterTestProbability();
+
+public:
+ static int getSplitterSelection() { return splitter_crit; }
+ static void setSplitterSelection( int criterion ) { splitter_crit = criterion; }
+
+ static int getSampleSize() { return sample_size; }
+ static void setSampleSize( int siz ) { sample_size = siz; }
+
+ static int getTriangulationFlag() { return triangulate_all; }
+ static void setTriangulationFlag( int flag ) { triangulate_all = flag; }
+
+ static int getNormalizeVectorsFlag() { return normalize_vectors; }
+ static void setNormalizeVectorsFlag( int flag ) { normalize_vectors = flag; }
+
+ static int getDisplayMessagesFlag() { return display_messages; }
+ static void setDisplayMessagesFlag( int flag ) { display_messages = flag; }
+
+ static void ResetCallCount() { partition_callcount = 0; }
+
+private:
+ static int splitter_crit; // splitter selection criterion to use
+ static int sample_size; // sample size for splitter sampling
+ static int triangulate_all; // triangulate polygons with more than three vertices
+ static int normalize_vectors; // always normalize direction vectors
+ static int display_messages; // display a message every time PartitionSpace() is invoked
+ static int partition_callcount;// call counter for PartitionSpace()
+ static int test_probability; // probability to test single polygon if SPLITTERCRIT_RANDOM_SAMPLE
+ static char str_scratchpad[]; // string scratch pad
+
+private:
+ int polygonno; // global number of this polygon
+ int faceno; // global number of face this polygon is contained in
+ int numpolygons; // length of singly linked polygon list
+ int numvertindxs; // number of entries in vertex index list attached to this polygon
+ VIndx* vertindxs; // pointer to first VIndx
+ VIndx* vindxinsertpos; // pointer to last VIndx (NULL means insert-position is at head)
+ BspObject* baseobject; // pointer to object this polygon belongs to
+ Polygon* nextpolygon; // pointer to next polygon in list
+};
+
+// determine if the polygon has area ------------------------------------------
+inline int Polygon::HasArea() const
+{
+ // collinear vertices are not checked here, the polygon need only have
+ // at least three vertices to count as having area!
+ return ( vertindxs && vertindxs->getNext() && vertindxs->getNext()->getNext() );
+}
+
+// get first vertex of polygon ------------------------------------------------
+inline int Polygon::getFirstVertexIndx() const
+{
+ CHECK_DEREFERENCING(
+ if ( vertindxs == NULL )
+ Error();
+ );
+ return vertindxs->getIndx();
+}
+inline Vertex3 Polygon::getFirstVertex() const
+{
+ CHECK_DEREFERENCING(
+ if ( vertindxs == NULL )
+ Error();
+ );
+ return ((Polygon *const)this)->getVertexList()[ vertindxs->getIndx() ];
+}
+
+// get second vertex of polygon -----------------------------------------------
+inline int Polygon::getSecondVertexIndx() const
+{
+ CHECK_DEREFERENCING(
+ if ( ( vertindxs == NULL ) || ( vertindxs->getNext() == NULL ) )
+ Error();
+ );
+ return vertindxs->getNext()->getIndx();
+}
+inline Vertex3 Polygon::getSecondVertex() const
+{
+ CHECK_DEREFERENCING(
+ if ( ( vertindxs == NULL ) || ( vertindxs->getNext() == NULL ) )
+ Error();
+ );
+ return ((Polygon *const)this)->getVertexList()[ vertindxs->getNext()->getIndx() ];
+}
+
+// get third vertex of polygon ------------------------------------------------
+inline int Polygon::getThirdVertexIndx() const
+{
+ CHECK_DEREFERENCING(
+ if ( ( vertindxs == NULL ) ||
+ ( vertindxs->getNext() == NULL ) ||
+ ( vertindxs->getNext()->getNext() == NULL ) )
+ Error();
+ );
+ return vertindxs->getNext()->getNext()->getIndx();
+}
+inline Vertex3 Polygon::getThirdVertex() const
+{
+ CHECK_DEREFERENCING(
+ if ( ( vertindxs == NULL ) ||
+ ( vertindxs->getNext() == NULL ) ||
+ ( vertindxs->getNext()->getNext() == NULL ) )
+ Error();
+ );
+ return ((Polygon *const)this)->getVertexList()[ vertindxs->getNext()->getNext()->getIndx() ];
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _POLYGON_H_
+
diff --git a/tool_src/BspLib/PolygonList.cpp b/tool_src/BspLib/PolygonList.cpp
new file mode 100644
index 0000000..4233c42
--- /dev/null
+++ b/tool_src/BspLib/PolygonList.cpp
@@ -0,0 +1,213 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: PolygonList.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "PolygonList.h"
+#include "BspObject.h"
+#include "BspTool.h"
+#include "BSPNode.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// init with already existing list of polygons --------------------------------
+//
+Polygon *PolygonListRep::InitList( Polygon *listhead )
+{
+ delete list;
+ list = listhead;
+ numpolygons = list ? list->getNumPolygons() : 0;
+
+ return list;
+}
+
+
+// merge another polygon list into this list ----------------------------------
+//
+void PolygonListRep::MergeLists( PolygonListRep *mergelist )
+{
+ if ( list != NULL ) {
+ // scan to end of local list
+ Polygon *poly = NULL;
+ for (poly = list; poly->getNext(); poly = poly->getNext() )
+ poly->setNumPolygons( poly->getNumPolygons() + mergelist->numpolygons );
+ // append mergelist
+ poly->setNext( mergelist->list );
+ poly->setNumPolygons( poly->getNumPolygons() + mergelist->numpolygons );
+ numpolygons += mergelist->numpolygons;
+ } else {
+ // local list is empty: simply take over mergelist
+ list = mergelist->list;
+ numpolygons = mergelist->numpolygons;
+ }
+}
+
+
+// create new polygon and add at head of list ---------------------------------
+//
+Polygon *PolygonListRep::NewPolygon()
+{
+ list = list ? list->NewPolygon() : new Polygon( baseobject );
+ numpolygons = list->getNumPolygons();
+
+ return list;
+}
+
+
+// insert existing polygon at head of list ------------------------------------
+//
+Polygon *PolygonListRep::InsertPolygon( Polygon *poly )
+{
+ if ( poly != NULL ) {
+
+ if ( list != NULL ) {
+ list = list->InsertPolygon( poly );
+ } else {
+ poly->setNext( NULL );
+ poly->setNumPolygons( 1 );
+ poly->baseobject = baseobject;
+ list = poly;
+ }
+ numpolygons = list->getNumPolygons();
+ }
+
+ return list;
+}
+
+
+// unlink head from list and return pointer to it -----------------------------
+//
+Polygon *PolygonListRep::UnlinkHead()
+{
+ Polygon *tmp = list;
+
+ if ( tmp != NULL ) {
+ list = tmp->getNext();
+ tmp->setNumPolygons( 1 );
+ tmp->setNext( NULL );
+ numpolygons = list ? list->getNumPolygons() : 0;
+ }
+
+ return tmp;
+}
+
+
+// delete head of list and return pointer to rest of list ---------------------
+//
+Polygon *PolygonListRep::DeleteHead()
+{
+ if ( list != NULL ) {
+ list = list->DeleteHead();
+ numpolygons = list ? list->getNumPolygons() : 0;
+ }
+
+ return list;
+}
+
+
+// calculate plane normals for planes of all polygons -------------------------
+//
+Polygon *PolygonListRep::CalcPlaneNormals()
+{
+ if ( list != NULL ) {
+ list->CalcPlaneNormals();
+ }
+
+ return list;
+}
+
+
+// check polygon planes for all polygons contained in list --------------------
+//
+Polygon *PolygonListRep::CheckPolygonPlanes()
+{
+ if ( list != NULL ) {
+ // list possibly grows due to checking planes!!
+ list = list->CheckPlanesAndMappings();
+ numpolygons = list->getNumPolygons();
+ }
+
+ return list;
+}
+
+
+// build bsp tree; polygon list is resolved in the process --------------------
+//
+BSPNode *PolygonListRep::PartitionSpace()
+{
+ BSPNode *bspnode = NULL;
+
+ if ( list != NULL ) {
+
+ if ( list->getSplitterSelection() == Polygon::SPLITTERCRIT_RANDOM_SAMPLE ) {
+ // calculate random sample probability
+ list->CalcSplitterTestProbability();
+ }
+
+ bspnode = list->PartitionSpace();
+ list = NULL;
+ numpolygons = 0;
+ //NOTE:
+ // the polygon list is resolved in the process of
+ // bsp compilation! polygons are only accessible as
+ // elements of the newly created bsp tree afterwards.
+ }
+
+ return bspnode;
+}
+
+
+// write list of polygon numbers to text-file (reverse ordering) --------------
+//
+void PolygonListRep::WritePolyList( FILE *fp, int no ) const
+{
+ if ( list != NULL ) {
+ if ( list->nextpolygon )
+ list->nextpolygon->WritePolyList( fp );
+ fprintf( fp, "%d\t\t; %d\n", list->getId() + 1, no );
+ }
+}
+
+
+// class PolygonList error message handler ------------------------------------
+//
+void PolygonListRep::Error( int err ) const
+{
+ {
+ StrScratch line;
+
+ switch ( err ) {
+
+ case E_NEWVINDX:
+ strcpy( line, "***ERROR*** in PolygonList::(Append|Prepend)NewVIndx()\n" );
+ break;
+
+ case E_APPENDVINDX:
+ strcpy( line, "***ERROR*** in PolygonList::AppendVIndx()\n" );
+ break;
+
+ case E_GETNUMVERTXS:
+ strcpy( line, "***ERROR*** in PolygonList::getNumElements()\n" );
+ break;
+
+ default:
+ strcpy( line, "***ERROR*** in object of class BspLib::PolygonList\n" );
+ break;
+ }
+
+ ErrorMessage( line );
+ }
+
+ HandleCriticalError();
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/PolygonList.h b/tool_src/BspLib/PolygonList.h
new file mode 100644
index 0000000..c06ec8c
--- /dev/null
+++ b/tool_src/BspLib/PolygonList.h
@@ -0,0 +1,153 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: PolygonList.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _POLYGONLIST_H_
+#define _POLYGONLIST_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Polygon.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+class BSPNode;
+class BspObject;
+
+
+// singly linked polygon list (representation class) --------------------------
+//
+class PolygonListRep : public virtual SystemIO {
+
+ friend class PolygonList;
+
+ // error codes
+ enum {
+ E_NEWVINDX,
+ E_APPENDVINDX,
+ E_GETNUMVERTXS
+ };
+
+ // error handler for class PolygonList
+ void Error( int err ) const;
+
+private:
+ PolygonListRep( BspObject *bobj );
+ ~PolygonListRep() { delete list; }
+
+ void MergeLists( PolygonListRep *mergelist );
+
+ Polygon* InitList( Polygon *listhead );
+
+ // invalidate list without freeing dynamic storage
+ void InvalidateList() { list = NULL; numpolygons = 0; }
+
+ Polygon* FetchHead() { return list; }
+ Polygon* UnlinkHead();
+ Polygon* DeleteHead();
+ Polygon* FindPolygon( int id ) { return list ? list->FindPolygon( id ) : NULL; }
+
+ Polygon* NewPolygon();
+ Polygon* InsertPolygon( Polygon *poly );
+
+ void PrependNewVIndx( int indx = -1 ) { if ( list == NULL ) Error( E_NEWVINDX ); list->PrependNewVIndx( indx ); }
+ void AppendNewVIndx( int indx = -1 ) { if ( list == NULL ) Error( E_NEWVINDX ); list->AppendNewVIndx( indx ); }
+ void AppendVIndx( VIndx *vindx ) { if ( list == NULL ) Error( E_APPENDVINDX ); list->AppendVIndx( vindx ); }
+ Polygon* CalcPlaneNormals();
+ Polygon* CheckPolygonPlanes();
+ BSPNode* PartitionSpace();
+
+ void WritePolyList( FILE *fp, int no ) const;
+
+ int getNumElements() const { return numpolygons; }
+ int getNumVertices() const { if( list == NULL ) Error( E_GETNUMVERTXS ); return list->getNumVertices(); }
+
+private:
+ int ref_count; // number of references to this list
+ int numpolygons; // length of singly linked polygon list (not counting this head)
+ BspObject* baseobject; // this list contains polygons belonging to *baseobject
+ Polygon* list; // pointer to first polygon in list
+};
+
+// constructor without preexisting list ---------------------------------------
+inline PolygonListRep::PolygonListRep( BspObject *bobj ) : ref_count( 0 )
+{
+ baseobject = bobj;
+ list = NULL;
+ numpolygons = 0;
+}
+
+
+// singly linked polygon list (handle class) ----------------------------------
+//
+class PolygonList {
+
+public:
+ PolygonList( BspObject *bobj ) { rep = new PolygonListRep( bobj ); rep->ref_count = 1; }
+ ~PolygonList() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ PolygonList( const PolygonList& copyobj );
+ PolygonList& operator =( const PolygonList& copyobj );
+
+ void MergeLists( PolygonList *mergelist ) { if ( mergelist ) rep->MergeLists( mergelist->rep ); }
+
+ Polygon* InitList( Polygon *listhead ) { return rep->InitList( listhead ); }
+ void InvalidateList() { rep->InvalidateList(); }
+
+ Polygon* FetchHead() { return rep->FetchHead(); }
+ Polygon* UnlinkHead() { return rep->UnlinkHead(); }
+ Polygon* DeleteHead() { return rep->DeleteHead(); }
+ Polygon* FindPolygon( int id ) { return rep->FindPolygon( id ); }
+
+ Polygon* NewPolygon() { return rep->NewPolygon(); }
+ Polygon* InsertPolygon( Polygon *poly ) { return rep->InsertPolygon( poly ); }
+
+ void PrependNewVIndx( int indx = -1 ) { rep->PrependNewVIndx( indx ); }
+ void AppendNewVIndx( int indx = -1 ) { rep->AppendNewVIndx( indx ); }
+ void AppendVIndx( VIndx *vindx ) { rep->AppendVIndx( vindx ); }
+ Polygon* CalcPlaneNormals() { return rep->CalcPlaneNormals(); }
+ Polygon* CheckPolygonPlanes() { return rep->CheckPolygonPlanes(); }
+ BSPNode* PartitionSpace() { return rep->PartitionSpace(); }
+
+ void WritePolyList( FILE *fp, int no ) const { rep->WritePolyList( fp, no ); }
+
+ int getNumElements() const { return rep->getNumElements(); }
+ int getNumVertices() const { return rep->getNumVertices(); }
+
+private:
+ PolygonListRep* rep;
+};
+
+// copy constructor for PolygonList -------------------------------------------
+inline PolygonList::PolygonList( const PolygonList& copyobj )
+{
+ rep = copyobj.rep; // shallow copy
+ rep->ref_count++; // with reference counting
+}
+
+// assignment operator for PolygonList ----------------------------------------
+inline PolygonList& PolygonList::operator =( const PolygonList& copyobj )
+{
+ if ( &copyobj != this ) {
+ // old reference is overwritten
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep; // shallow copy
+ rep->ref_count++; // with reference counting
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _POLYGONLIST_H_
+
diff --git a/tool_src/BspLib/SingleFormat.cpp b/tool_src/BspLib/SingleFormat.cpp
new file mode 100644
index 0000000..f1db564
--- /dev/null
+++ b/tool_src/BspLib/SingleFormat.cpp
@@ -0,0 +1,158 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: SingleFormat.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "SingleFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct class SingleFormat by initializing Single specific members -------------
+//
+inline SingleFormatBase::SingleFormatBase()
+{
+ strcpy( xchangecmd, "xyz" );
+
+ AxesDirSwitch = Vertex3( 1.0, 1.0, 1.0 );
+
+ ObjScaleX = 1.0;
+ ObjScaleY = 1.0;
+ ObjScaleZ = 1.0;
+
+ NewOriginX = 0.0;
+ NewOriginY = 0.0;
+ NewOriginZ = 0.0;
+
+ worldlocation_set = FALSE;
+ camera_set = FALSE;
+ xchange_set = FALSE;
+ scalefactors_set = FALSE;
+ setorigin_set = FALSE;
+
+ // init default world and view matrix
+ for ( int j = 0; j < 4; j++ ) {
+ for ( int i = 0; i < 4; i++ ) {
+ int indx = j * 4 + i;
+ vm[ indx ] = wm[ indx ] = ( j == i ) ? 1.0 : 0.0;
+ }
+ }
+}
+
+
+// constructor for SingleFormat -----------------------------------------------
+//
+SingleFormat::SingleFormat()
+{
+ // all initializations are done
+ // in SingleFormatBase::SingleFormatBase()
+}
+
+
+// copy constructor for SingleFormat ------------------------------------------
+//
+SingleFormat::SingleFormat( const SingleFormat& copyobj ) :
+ SingleFormatBase( copyobj ),
+ m_palette_fname( copyobj.m_palette_fname )
+{
+}
+
+
+// assignment operator for SingleFormat ---------------------------------------
+//
+SingleFormat& SingleFormat::operator =( const SingleFormat& copyobj )
+{
+ if ( &copyobj != this ) {
+ *(SingleFormatBase *)this = copyobj;
+ m_palette_fname = copyobj.m_palette_fname;
+ }
+ return *this;
+}
+
+
+// get index to section id specified as string (this function is static!) -----
+//
+int SingleFormat::GetSectionId( char *section_name )
+{
+ for ( int i = _nil + 1; i < _num_single_sections; i++ )
+ if ( stricmp( section_name, section_strings[ i ] ) == 0 )
+ return section_ids[ i ];
+
+ // _nil means section name invalid, so no valid index can be returned
+ return _nil;
+}
+
+
+// get name of section specified via id (this function is static!) ------------
+//
+const char *SingleFormat::GetSectionName( int section_id )
+{
+ return ( section_id < _num_single_sections ) ? section_strings[ section_id ] : NULL;
+}
+
+
+// SingleFormat specific static variables -------------------------------------
+//
+
+// origin translation automatically applied to all objects
+const double SingleFormat::PREMOVEORIGIN_X = 0.0;
+const double SingleFormat::PREMOVEORIGIN_Y = 0.0;
+const double SingleFormat::PREMOVEORIGIN_Z = 0.0;
+
+// section names
+const char SingleFormat::_vertices_str[] = "#vertices";
+const char SingleFormat::_faces_str[] = "#faces";
+const char SingleFormat::_faceproperties_str[] = "#faceproperties";
+const char SingleFormat::_correspondences_str[] = "#correspondences";
+const char SingleFormat::_textures_str[] = "#textures";
+const char SingleFormat::_worldlocation_str[] = "#worldlocation";
+const char SingleFormat::_camera_str[] = "#camera";
+const char SingleFormat::_comment_str[] = "#comment";
+const char SingleFormat::_palette_str[] = "#palette";
+const char SingleFormat::_scalefactors_str[] = "#scalefactors";
+const char SingleFormat::_xchange_str[] = "#xchange";
+const char SingleFormat::_setorigin_str[] = "#setorigin";
+const char SingleFormat::_facenormals_str[] = "#facenormals";
+
+// section name table
+const char *SingleFormat::section_strings[] = {
+ NULL,
+ _vertices_str,
+ _faces_str,
+ _faceproperties_str,
+ _correspondences_str,
+ _textures_str,
+ _worldlocation_str,
+ _camera_str,
+ _comment_str,
+ _palette_str,
+ _scalefactors_str,
+ _xchange_str,
+ _setorigin_str,
+ _facenormals_str
+};
+const int SingleFormat::section_ids[] = {
+ _nil,
+ _vertices,
+ _faces,
+ _faceproperties,
+ _correspondences,
+ _textures,
+ _worldlocation,
+ _camera,
+ _comment,
+ _palette,
+ _scalefactors,
+ _xchange,
+ _setorigin,
+ _facenormals
+};
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/SingleFormat.h b/tool_src/BspLib/SingleFormat.h
new file mode 100644
index 0000000..36d7fdd
--- /dev/null
+++ b/tool_src/BspLib/SingleFormat.h
@@ -0,0 +1,119 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: SingleFormat.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _SINGLEFORMAT_H_
+#define _SINGLEFORMAT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// baseclass for single format type file input/output -------------------------
+//
+class SingleFormatBase {
+
+ friend class SingleFormat;
+
+private:
+ SingleFormatBase();
+ ~SingleFormatBase() { }
+
+protected:
+ char xchangecmd[4];
+
+ Vertex3 AxesDirSwitch;
+
+ double ObjScaleX;
+ double ObjScaleY;
+ double ObjScaleZ;
+
+ double NewOriginX;
+ double NewOriginY;
+ double NewOriginZ;
+
+ int worldlocation_set;
+ int camera_set;
+ int xchange_set;
+ int scalefactors_set;
+ int setorigin_set;
+
+ hprec_t wm[16]; // world matrix
+ hprec_t vm[16]; // view matrix
+};
+
+class SingleFormat : public SingleFormatBase {
+
+protected:
+
+ // section enumeration
+ enum {
+ _nil,
+ _vertices,
+ _faces,
+ _faceproperties,
+ _correspondences,
+ _textures,
+ _worldlocation,
+ _camera,
+ _comment,
+ _palette,
+ _scalefactors,
+ _xchange,
+ _setorigin,
+ _facenormals,
+
+ _num_single_sections
+ };
+
+public:
+ SingleFormat();
+ ~SingleFormat() { }
+
+ SingleFormat( const SingleFormat& copyobj );
+ SingleFormat& operator =( const SingleFormat& copyobj );
+
+protected:
+ String m_palette_fname;
+
+protected:
+ static int GetSectionId( char *section_name );
+ static const char* GetSectionName( int section_id );
+
+protected:
+ static const double PREMOVEORIGIN_X;
+ static const double PREMOVEORIGIN_Y;
+ static const double PREMOVEORIGIN_Z;
+
+ static const char _vertices_str[];
+ static const char _faces_str[];
+ static const char _faceproperties_str[];
+ static const char _correspondences_str[];
+ static const char _textures_str[];
+ static const char _worldlocation_str[];
+ static const char _camera_str[];
+ static const char _comment_str[];
+ static const char _palette_str[];
+ static const char _scalefactors_str[];
+ static const char _xchange_str[];
+ static const char _setorigin_str[];
+ static const char _facenormals_str[];
+
+ static const char* section_strings[];
+ static const int section_ids[];
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _SINGLEFORMAT_H_
+
diff --git a/tool_src/BspLib/SingleInput.cpp b/tool_src/BspLib/SingleInput.cpp
new file mode 100644
index 0000000..1f13616
--- /dev/null
+++ b/tool_src/BspLib/SingleInput.cpp
@@ -0,0 +1,699 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: SingleInput.cpp
+//
+// Copyright (c) 1996-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "SingleInput.h"
+#include "BspObject.h"
+#include "BspTool.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file is read and parsed immediately after construction of an object --------
+//
+SingleInput::SingleInput( BspObjectList objectlist, const char *filename ) :
+ InputData3D( objectlist, filename, DONT_CREATE_OBJECT ),
+ m_baseobject( objectlist.CreateNewObject() ),
+ m_input( filename, "r" )
+{
+ m_parser_lineno = 0;
+ ParseObjectData();
+}
+
+
+// destructor destroys only class members and the base classes ----------------
+//
+SingleInput::~SingleInput()
+{
+}
+
+
+// convert color indexes to rgb values ----------------------------------------
+//
+int SingleInput::ConvertColIndxs()
+{
+ // do colorindex to rgb conversion
+ if ( m_palette_fname != NULL ) {
+ char *palette = new char[ 256 * 3 ];
+ FileAccess palfile( m_palette_fname, "rb", 0 );
+ if ( palfile.Status() == SYSTEM_IO_OK ) {
+ if ( palfile.Read( palette, 3, 256 ) != SYSTEM_IO_OK ) {
+ if ( getRGBConversionFlag() )
+ ErrorMessage( "Specified palette invalid or read error.\n" );
+ delete palette;
+ return FALSE;
+ } else if ( m_baseobject->ConvertColorIndexesToRGB( palette, getRGBConversionFlag() ) ) {
+ if ( getRGBConversionFlag() )
+ InfoMessage( "Color indexes converted to RGB triplets.\n" );
+ delete palette;
+ }
+ } else {
+ if ( getRGBConversionFlag() )
+ ErrorMessage( "Specified palette not found.\n" );
+ delete palette;
+ return FALSE;
+ }
+ } else {
+ if ( getRGBConversionFlag() )
+ ErrorMessage( "Conversion col-indexes to RGB triplets desired, but no palette set!\n" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// apply translation specified as origin --------------------------------------
+//
+void SingleInput::ApplyOriginTranslation()
+{
+ //CAVEAT:
+ // this will corrupt explicit separator planes and bounding boxes.
+ // thus, it must only be used for files where these two data types
+ // don't occur!
+
+ // scan all vertices and translate them
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ for ( int i = 0; i < vtxlist.getNumElements(); i++ ) {
+ vtxlist[ i ].setX( vtxlist[ i ].getX() - NewOriginX );
+ vtxlist[ i ].setY( vtxlist[ i ].getY() - NewOriginY );
+ vtxlist[ i ].setZ( vtxlist[ i ].getZ() - NewOriginZ );
+ }
+ NewOriginX = NewOriginY = NewOriginZ = 0.0;
+}
+
+
+// filter direction switches for axes -----------------------------------------
+//
+void SingleInput::FilterAxesDirSwitch()
+{
+ //CAVEAT:
+ // this will corrupt explicit separator planes, bounding boxes,
+ // and affine mappings. thus, it must only be used for files
+ // where these three data types don't occur!
+
+ if ( PostProcessingFlags & FILTER_AXES_DIR_SWITCH ) {
+
+ //NOTE:
+ // axis direction switches (negative object scale factors)
+ // are only filtered here. that is, they don't make it into
+ // the output file. they are only applied to the object if
+ // FILTER_AXES_EXCHANGE is also specified!
+
+ // filter direction switches of axes
+ double xc = ( ObjScaleX < 0 ) ? -1.0 : 1.0;
+ double yc = ( ObjScaleY < 0 ) ? -1.0 : 1.0;
+ double zc = ( ObjScaleZ < 0 ) ? -1.0 : 1.0;
+
+ AxesDirSwitch = Vertex3( xc, yc, zc );
+
+ ObjScaleX *= xc;
+ ObjScaleY *= yc;
+ ObjScaleZ *= zc;
+ }
+}
+
+
+// filter object scale factors and apply them ---------------------------------
+//
+void SingleInput::FilterScaleFactors()
+{
+ //CAVEAT:
+ // this will corrupt explicit separator planes, bounding boxes,
+ // and affine mappings. thus, it must only be used for files
+ // where these three data types don't occur!
+
+ if ( PostProcessingFlags & FILTER_SCALE_FACTORS ) {
+ // scan all vertices and apply scale factors
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ for ( int i = 0; i < vtxlist.getNumElements(); i++ ) {
+ vtxlist[ i ].setX( vtxlist[ i ].getX() * ObjScaleX );
+ vtxlist[ i ].setY( vtxlist[ i ].getY() * ObjScaleY );
+ vtxlist[ i ].setZ( vtxlist[ i ].getZ() * ObjScaleZ );
+ }
+ // reset (filter) scale factors
+ ObjScaleX = ObjScaleY = ObjScaleZ = 1.0;
+ }
+}
+
+
+// exchange axes according to specification -----------------------------------
+//
+void SingleInput::FilterAxesExchange()
+{
+ //CAVEAT:
+ // this will corrupt explicit separator planes, bounding boxes,
+ // and affine mappings. thus, it must only be used for files
+ // where these three data types don't occur!
+
+ if ( PostProcessingFlags & FILTER_AXES_EXCHANGE ) {
+
+ // exchange axes by applying axes exchange command to every
+ // vertex. axis direction switches are also applied if they
+ // have been filtered previously (FILTER_AXES_DIR_SWITCH).
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ for ( int i = 0; i < vtxlist.getNumElements(); i++ )
+ vtxlist[ i ].ChangeAxes( xchangecmd, AxesDirSwitch );
+
+ // reset exchange command
+ strcpy( xchangecmd, "xyz" );
+ }
+}
+
+
+// enforce maximum extents for all coordinates --------------------------------
+//
+void SingleInput::EnforceMaximumExtents()
+{
+ if ( PostProcessingFlags & FORCE_MAXIMUM_EXTENT ) {
+ // calculate scale factor for entire object
+ double fmext = getMaxExtents();
+ double mext = m_maximumextents.getX();
+ if ( m_maximumextents.getY() > mext ) mext = m_maximumextents.getY();
+ if ( m_maximumextents.getZ() > mext ) mext = m_maximumextents.getZ();
+ double cfac = fmext / ( 2 * mext );
+ // scan all vertices and apply scale factor
+ VertexChunk& vtxlist = m_baseobject->getVertexList();
+ for ( int i = 0; i < vtxlist.getNumElements(); i++ ) {
+ vtxlist[ i ].setX( vtxlist[ i ].getX() * cfac );
+ vtxlist[ i ].setY( vtxlist[ i ].getY() * cfac );
+ vtxlist[ i ].setZ( vtxlist[ i ].getZ() * cfac );
+ }
+ // apply scale factor to separator planes and
+ // bounding boxes of bsp tree nodes
+ m_baseobject->getBSPTreeFlat().ApplyScaleFactor( cfac );
+ }
+}
+
+
+// print error message if error in object data-file ---------------------------
+//
+void SingleInput::ParseError( int section )
+{
+ sprintf( line, "%sin section %s (line %d)", parser_err_str,
+ GetSectionName( section ), m_parser_lineno );
+ ErrorMessage( line );
+ HandleCriticalError();
+}
+
+
+// read single integer parameter ----------------------------------------------
+//
+void SingleInput::ReadIntParameter( int& param, int lowbound )
+{
+ char *remptr;
+ int fno = strtol( m_scanptr, &remptr, 10 );
+ if ( ( *remptr != '\0' ) || ( fno < lowbound ) )
+ ParseError( m_section );
+ param = fno - lowbound;
+}
+
+
+// read single floating point parameter ---------------------------------------
+//
+void SingleInput::ReadFloatParameter( double& param )
+{
+ char *remptr;
+ param = strtod( m_scanptr, &remptr );
+ if ( *remptr != '\0' )
+ ParseError( m_section );
+}
+
+
+// read two adjacent double values --------------------------------------------
+//
+void SingleInput::ReadTwoDoubles( double& x, double& y )
+{
+ ReadFloatParameter( x );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( y );
+}
+
+
+// read three adjacent double values ------------------------------------------
+//
+void SingleInput::ReadThreeDoubles( double& x, double& y, double& z )
+{
+ ReadFloatParameter( x );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( y );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( z );
+}
+
+
+// read four adjacent double values -------------------------------------------
+//
+void SingleInput::ReadFourDoubles( double& x, double& y, double& z, double& d )
+{
+ ReadFloatParameter( x );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( y );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( z );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( d );
+}
+
+
+// read six adjacent double values --------------------------------------------
+//
+void SingleInput::ReadSixDoubles( Vertex3& v1, Vertex3& v2 )
+{
+ double rdoub;
+
+ ReadFloatParameter( rdoub );
+ v1.setX( rdoub );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( rdoub );
+ v1.setY( rdoub );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( rdoub );
+ v1.setZ( rdoub );
+
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( rdoub );
+ v2.setX( rdoub );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( rdoub );
+ v2.setY( rdoub );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( rdoub );
+ v2.setZ( rdoub );
+}
+
+
+// read three vertices specified in x y z order -------------------------------
+//
+void SingleInput::ReadVertex()
+{
+ double x, y, z;
+ ReadThreeDoubles( x, y, z );
+
+ double absx = fabs( x );
+ double absy = fabs( y );
+ double absz = fabs( z );
+
+ double mx = ( absx > m_maximumextents.getX() ) ? absx : m_maximumextents.getX();
+ double my = ( absy > m_maximumextents.getY() ) ? absy : m_maximumextents.getY();
+ double mz = ( absz > m_maximumextents.getZ() ) ? absz : m_maximumextents.getZ();
+
+ m_maximumextents = Vertex3( mx, my, mz );
+ m_baseobject->getVertexList().AddVertex( Vertex3( x, y, z ) );
+}
+
+
+// read face normal from file -------------------------------------------------
+//
+void SingleInput::ReadFaceNormal( int& normalsread )
+{
+ // read normal coordinates
+ double x, y, z;
+ ReadThreeDoubles( x, y, z );
+
+ // build normal
+ Vector3 normal( x, y, z );
+
+ // insert face into facelist
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ if ( facelist.getNumElements() > normalsread ) {
+ // do nothing if normal already valid
+ if ( !facelist[ normalsread ].NormalValid() ) {
+ // attach normal to existing face
+ facelist[ normalsread ].AttachNormal( normal );
+ }
+ } else {
+ // create face containing only normal info
+ Face tempface;
+ tempface.AttachNormal( normal );
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+ }
+ normalsread++;
+}
+
+
+// read vertex indexes comprising a face --------------------------------------
+//
+void SingleInput::ReadFace( int aod_read )
+{
+ // add new polygon to list
+ Polygon *poly = m_baseobject->getPolygonList().NewPolygon();
+
+ // if not aod format, set face id to "invalid"
+ if ( !aod_read )
+ poly->setFaceId( -1 );
+
+ // create vertexlist for this polygon
+ while ( m_scanptr != NULL ) {
+ if ( *m_scanptr == ';' )
+ break;
+ char *remptr;
+ int fno = strtol( m_scanptr, &remptr, 10 );
+ if ( ( *remptr != '\0') || ( fno < 1 ) )
+ ParseError( m_section );
+
+ // store vertex index (converted to 0-base)
+ m_baseobject->getPolygonList().AppendNewVIndx( fno - 1 );
+ m_scanptr = strtok( NULL, ",/ \t\n\r" );
+ }
+
+ // check if face is either triangle or quadrilateral
+ if ( aod_read && !getAllowNGonFlag() ) {
+ int vnum = m_baseobject->getPolygonList().getNumVertices();
+ if ( ( vnum < 3 ) || ( vnum > 4 ) ) {
+ sprintf( line, "%s[Face must be triangle or quadrilateral]: %d",
+ parser_err_str, m_baseobject->getPolygonList().getNumElements() );
+ ErrorMessage( line );
+ HandleCriticalError();
+ }
+ }
+}
+
+
+// read RGBA quadruplet for material ------------------------------------------
+//
+void SingleInput::ReadMaterialRGBA( ColorRGBA &col, int indx )
+{
+ double c_r, c_g, c_b, c_a;
+ if ( strcmp( m_scanptr, Face::material_strings[ indx ] ) != 0 )
+ ParseError( m_section );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFourDoubles( c_r, c_g, c_b, c_a );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+
+ col.R = (byte)( c_r * 255 );
+ col.G = (byte)( c_g * 255 );
+ col.B = (byte)( c_b * 255 );
+ col.A = (byte)( c_a * 255 );
+}
+
+
+// read material properties of a face -----------------------------------------
+//
+void SingleInput::ReadFaceProperties( int& facepropsread )
+{
+ // face to create
+ Face tempface;
+
+ // convert shading type string to type id
+ int shadingtypeid = tempface.GetTypeIndex( m_scanptr );
+ if ( shadingtypeid < 0 ) {
+ sprintf( line, "%s[Undefined face-property]: %s (line %d)",
+ parser_err_str, m_scanptr, m_parser_lineno );
+ ErrorMessage( line );
+ HandleCriticalError();
+ }
+
+ // set shading type for face
+ tempface.setShadingType( shadingtypeid );
+
+ // read color if necessary for shading type
+ if ( shadingtypeid & Face::color_mask ) {
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+
+ // determine how color is specified
+ int readrgb = 0;
+ if ( isalpha( *m_scanptr ) ) {
+ int colormodel = tempface.GetColorModelIndex( m_scanptr );
+ switch ( colormodel ) {
+ case Face::rgb_col:
+ readrgb = 1;
+ break;
+ case Face::indexed_col:
+ readrgb = 0;
+ break;
+ case Face::material_col:
+ readrgb = 2;
+ break;
+ default:
+ ParseError( m_section );
+ }
+
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ }
+
+ // read color in specified (detected) model
+ if ( readrgb == 1 ) {
+ // read (r,g,b) triplet
+ double col_r, col_g, col_b;
+ ReadThreeDoubles( col_r, col_g, col_b );
+ ColorRGBA rgba_col;
+ rgba_col.R = (byte) ( col_r * 255 );
+ rgba_col.G = (byte) ( col_g * 255 );
+ rgba_col.B = (byte) ( col_b * 255 );
+ rgba_col.A = 255;
+ tempface.setFaceColor( rgba_col );
+ } else if ( readrgb == 2 ) {
+ // read material specification
+ Material *mat = new Material;
+ ColorRGBA colquad;
+ ReadMaterialRGBA( colquad, 0 );
+ mat->setAmbientColor( colquad );
+ ReadMaterialRGBA( colquad, 1 );
+ mat->setDiffuseColor( colquad );
+ ReadMaterialRGBA( colquad, 2 );
+ mat->setSpecularColor( colquad );
+ ReadMaterialRGBA( colquad, 3 );
+ mat->setEmissiveColor( colquad );
+ if ( strcmp( m_scanptr, Face::material_strings[ 4 ] ) != 0 )
+ ParseError( m_section );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ double floatpara;
+ ReadFloatParameter( floatpara );
+ mat->setShininess( (float) floatpara );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ if ( strcmp( m_scanptr, Face::material_strings[ 5 ] ) != 0 )
+ ParseError( m_section );
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ ReadFloatParameter( floatpara );
+ mat->setTransparency( (float) floatpara );
+ // attach material
+ tempface.AttachMaterial( mat );
+ } else {
+ // read color index
+ char *remptr;
+ int fno = strtol( m_scanptr, &remptr, 10 );
+ if ( *remptr != '\0' )
+ ParseError( m_section );
+ tempface.setFaceColor( fno );
+ }
+
+ }
+
+ // read texture name if necessary for shading type
+ if ( shadingtypeid & Face::texmap_mask ) {
+ while ( *m_scanptr++ != '\0' ) ;
+ while ( ( *m_scanptr == ' ' ) || ( *m_scanptr == '\t' ) )
+ m_scanptr++;
+ if ( ( m_scanptr = strtok( m_scanptr, "\"" ) ) == NULL )
+ ParseError( m_section );
+ tempface.setTextureName( m_scanptr );
+ }
+
+ // insert face into facelist
+ FaceChunk& facelist = m_baseobject->getFaceList();
+ if ( facelist.getNumElements() > facepropsread ) {
+ if ( facelist[ facepropsread ].NormalValid() ) {
+ // take over normal if one has already been calculated
+ Vector3 normal = facelist[ facepropsread ].getPlaneNormal();
+ tempface.AttachNormal( normal );
+ }
+ tempface.setId( facelist[ facepropsread ].getId() );
+ facelist[ facepropsread ] = tempface;
+ } else {
+ tempface.setId( facelist.getNumElements() );
+ facelist.AddElement( tempface );
+ }
+ facepropsread++;
+}
+
+
+// read vertex correspondences specifying a mapping ---------------------------
+//
+void SingleInput::ReadCorrespondences()
+{
+ Mapping tempmapping;
+
+ // read vertexindexes for this face mapping (one line!)
+ while ( m_scanptr != NULL ) {
+ if ( *m_scanptr == ';' )
+ break;
+ int vertexno;
+ ReadIntParameter( vertexno, 1 );
+ tempmapping.InsertFaceVertex( vertexno );
+ m_scanptr = strtok( NULL, ",/ \t\n\r" );
+ }
+
+ // read correspondences for all vertexindexes
+ // (each correspondence has to be specified on a separate line!)
+ for ( int k = 0; k < tempmapping.getNumVertices(); k++ ) {
+ if ( m_input.ReadLine( line, TEXTLINE_MAX ) == NULL )
+ ParseError( m_section );
+
+ ++m_parser_lineno;
+ if ( ( m_scanptr = strtok( line, ",/ \t\n\r" ) ) == NULL )
+ continue;
+
+ double u, v;
+ ReadTwoDoubles( u, v );
+ tempmapping.setMappingCoordinates( k, Vertex2( u, v ) );
+ }
+
+ m_baseobject->getMappingList().AddElement( tempmapping );
+}
+
+
+// read texture definitions ---------------------------------------------------
+//
+void SingleInput::ReadTextures()
+{
+ char *remptr;
+
+ int txwidth = strtol( m_scanptr, &remptr, 10 );
+ if ( *remptr != '\0' ) ParseError( m_section );
+
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+
+ int txheight = strtol( m_scanptr, &remptr, 10 );
+ if ( *remptr != '\0' ) ParseError( m_section );
+
+ Texture temptex( txwidth, txheight );
+
+ while ( *m_scanptr++ != '\0' ) ;
+ while ( ( *m_scanptr == ' ' ) || ( *m_scanptr == '\t' ) )
+ m_scanptr++;
+ if ( ( m_scanptr = strtok( m_scanptr, "\"" ) ) == NULL )
+ ParseError( m_section );
+ temptex.setName( m_scanptr );
+
+ if ( ( m_scanptr = strtok( NULL, ",/ \t\n\r" ) ) == NULL )
+ ParseError( m_section );
+ temptex.setFile( m_scanptr );
+
+ m_baseobject->getTextureList().AddElement( temptex );
+}
+
+
+// read initial world location for viewer -------------------------------------
+//
+void SingleInput::ReadWorldLocation()
+{
+ if ( worldlocation_set++ )
+ ParseError( m_section );
+ int i = 0;
+ while ( m_scanptr != NULL ) {
+ if ( *m_scanptr == ';' )
+ break;
+ if ( i > 15 ) // read 16 matrix elements
+ ParseError( m_section );
+ double fval;
+ ReadFloatParameter( fval );
+ wm[ i++ ] = fval;
+ m_scanptr = strtok( NULL, ",/ \t\n\r" );
+ }
+ if ( i != 16 )
+ ParseError( m_section );
+}
+
+
+// read initial camera location for viewer ------------------------------------
+//
+void SingleInput::ReadCameraLocation()
+{
+ if ( camera_set++ )
+ ParseError( m_section );
+ int i = 0;
+ while ( m_scanptr != NULL ) {
+ if ( *m_scanptr == ';' )
+ break;
+ if ( i > 15 ) // read 16 matrix elements
+ ParseError( m_section );
+ double fval;
+ ReadFloatParameter( fval );
+ vm[ i++ ] = fval;
+ m_scanptr = strtok( NULL, ",/ \t\n\r" );
+ }
+ if ( i != 16 )
+ ParseError( m_section );
+}
+
+
+// read filename of palette data ----------------------------------------------
+//
+void SingleInput::ReadPaletteFilename()
+{
+ if ( m_palette_fname != NULL )
+ ParseError( m_section );
+ m_palette_fname = new char[ strlen( m_scanptr ) + 1 ];
+ strcpy( m_palette_fname, m_scanptr );
+}
+
+
+// read object scale factors --------------------------------------------------
+//
+void SingleInput::ReadScaleFactors()
+{
+ if ( scalefactors_set++ )
+ ParseError( m_section );
+ ReadThreeDoubles( ObjScaleX, ObjScaleY, ObjScaleZ );
+}
+
+
+// read axes exchange command -------------------------------------------------
+//
+void SingleInput::ReadXChangeCommand()
+{
+ if ( xchange_set++ )
+ ParseError( m_section );
+ if ( strlen( m_scanptr ) > 3 )
+ ParseError( m_section );
+ strcpy( xchangecmd, m_scanptr );
+}
+
+
+// read origin translation ----------------------------------------------------
+//
+void SingleInput::ReadOrigin()
+{
+ if ( setorigin_set++ )
+ ParseError( m_section );
+ ReadThreeDoubles( NewOriginX, NewOriginY, NewOriginZ );
+ NewOriginX += PREMOVEORIGIN_X;
+ NewOriginY += PREMOVEORIGIN_Y;
+ NewOriginZ += PREMOVEORIGIN_Z;
+}
+
+
+// every PARSER_DOT_SIZE + 1 parsed lines a dot is printed (bitmask!!) --------
+//
+const int SingleInput::PARSER_DOT_SIZE = 0x1f;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/SingleInput.h b/tool_src/BspLib/SingleInput.h
new file mode 100644
index 0000000..41e4218
--- /dev/null
+++ b/tool_src/BspLib/SingleInput.h
@@ -0,0 +1,83 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: SingleInput.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _SINGLEINPUT_H_
+#define _SINGLEINPUT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "InputData3D.h"
+#include "SingleFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class providing single format type input capability ------------------------
+//
+class SingleInput : public InputData3D, public virtual SingleFormat {
+
+ friend class AodOutput;
+ friend class BspOutput;
+
+protected:
+ SingleInput( BspObjectList objectlist, const char *filename );
+ ~SingleInput();
+
+protected:
+ int ConvertColIndxs();
+ void ApplyOriginTranslation();
+ void FilterAxesDirSwitch();
+ void FilterScaleFactors();
+ void FilterAxesExchange();
+ void EnforceMaximumExtents();
+
+ virtual void ParseError( int section );
+ void ReadIntParameter( int& param, int lowbound );
+ void ReadFloatParameter( double& param );
+ void ReadTwoDoubles( double& x, double& y );
+ void ReadThreeDoubles( double& x, double& y, double& z );
+ void ReadFourDoubles( double& x, double& y, double& z, double& d );
+ void ReadSixDoubles( Vertex3& v1, Vertex3& v2 );
+
+ void ReadVertex();
+ void ReadFaceNormal( int& normalsread );
+ void ReadFace( int aod_read );
+ void ReadFaceProperties( int& facepropsread );
+ void ReadCorrespondences();
+ void ReadTextures();
+ void ReadWorldLocation();
+ void ReadCameraLocation();
+ void ReadPaletteFilename();
+ void ReadScaleFactors();
+ void ReadXChangeCommand();
+ void ReadOrigin();
+
+private:
+ void ReadMaterialRGBA( ColorRGBA &col, int indx );
+
+protected:
+ static const int PARSER_DOT_SIZE;
+
+protected:
+ BspObject* m_baseobject;
+ FileAccess m_input;
+
+ char* m_scanptr;
+ int m_section;
+ int m_parser_lineno;
+
+ Vertex3 m_maximumextents;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _SINGLEINPUT_H_
+
diff --git a/tool_src/BspLib/SingleOutput.cpp b/tool_src/BspLib/SingleOutput.cpp
new file mode 100644
index 0000000..0c0aa52
--- /dev/null
+++ b/tool_src/BspLib/SingleOutput.cpp
@@ -0,0 +1,125 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: SingleOutput.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "SingleOutput.h"
+#include "BspObject.h"
+#include "BspTool.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct SingleOutput object ----------------------------------------------
+//
+SingleOutput::SingleOutput( BspObjectList objectlist, const char *filename ) :
+ OutputData3D( objectlist, filename, DONT_CREATE_OBJECT ),
+ m_baseobject( objectlist.getListHead() ),
+ m_output( filename, "w" )
+{
+}
+
+
+// destroy SingleOutput object ------------------------------------------------
+//
+SingleOutput::~SingleOutput()
+{
+}
+
+
+// assignment copies only the SingleFormat part of the object -----------------
+//
+SingleOutput& SingleOutput::operator =( const SingleOutput& copyobj )
+{
+ *(SingleFormat *)this = copyobj;
+ return *this;
+}
+
+
+// write bsplib banner to file and init output data ---------------------------
+//
+void SingleOutput::InitOutput()
+{
+ String filename = BspTool::SkipPath( m_filename );
+
+ // write file's name
+ sprintf( line, "; %s ----------------------------------------------\n",
+ (const char *) filename );
+ m_output.WriteLine( line );
+
+ // write banner
+ sprintf( line, "; automatically created by BspLib V%s\n", version_str );
+ m_output.WriteLine( line );
+ m_output.WriteLine( "; Copyright (c) by Markus Hadwiger 1996-1998\n\n" );
+
+ // ensure correctness of attribute counts
+ m_baseobject->UpdateAttributeNumbers();
+}
+
+
+// write single format part of file for this object ---------------------------
+//
+int SingleOutput::WriteOutputFile()
+{
+
+#define sprintf m_output.WriteLine( line ); sprintf
+
+#ifndef SHORT_OUTPUT_FORMAT
+
+ strcpy( line, "\n" );
+
+ if ( m_palette_fname ) {
+ sprintf( line, "; name of palette file ---------------------------------------------------\n" );
+ sprintf( line, "%s\n", _palette_str );
+ sprintf( line, "%s\n", (const char *) m_palette_fname );
+ sprintf( line, "\n" );
+ }
+
+ sprintf( line, "; scale factors for each axis --------------------------------------------\n" );
+ sprintf( line, "%s\n", _scalefactors_str );
+ sprintf( line, "%f, %f, %f\n", ObjScaleX, ObjScaleY, ObjScaleZ );
+ sprintf( line, "\n" );
+
+ sprintf( line, "; translation of origin --------------------------------------------------\n" );
+ sprintf( line, "%s\n", _setorigin_str );
+ sprintf( line, "%f, %f, %f\n", NewOriginX, NewOriginY, NewOriginZ );
+ sprintf( line, "\n" );
+
+ sprintf( line, "; exchange command for axes ----------------------------------------------\n" );
+ sprintf( line, "%s\n", _xchange_str );
+ sprintf( line, "%s\n", xchangecmd );
+ sprintf( line, "\n" );
+
+ sprintf( line, "; starting object location in objectviewer -------------------------------\n" );
+ sprintf( line, "%s\n", _worldlocation_str );
+ int i = 0;
+ for ( i = 0; i < 15; i++ ) {
+ sprintf( line, "%f, ", wm[ i ] );
+ }
+ sprintf( line, "%f\n", wm[ 15 ] );
+ sprintf( line, "\n" );
+
+ sprintf( line, "; starting camera location in objectviewer -------------------------------\n" );
+ sprintf( line, "%s\n", _camera_str );
+ for ( i = 0; i < 15; i++ ) {
+ sprintf( line, "%f, ", vm[ i ] );
+ }
+ sprintf( line, "%f\n", vm[ 15 ] );
+ sprintf( line, "\n" );
+
+#endif
+
+ sprintf( line, "<end-of-file ------------------------------------------------------------------>\n" );
+ m_output.WriteLine( line );
+
+ return m_output.Status();
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/SingleOutput.h b/tool_src/BspLib/SingleOutput.h
new file mode 100644
index 0000000..4296c42
--- /dev/null
+++ b/tool_src/BspLib/SingleOutput.h
@@ -0,0 +1,44 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: SingleOutput.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _SINGLEOUTPUT_H_
+#define _SINGLEOUTPUT_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BspObject.h"
+#include "OutputData3D.h"
+#include "SingleFormat.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// class providing single format type output capability -----------------------
+//
+class SingleOutput : public OutputData3D, public virtual SingleFormat {
+
+protected:
+ SingleOutput( BspObjectList objectlist, const char *filename );
+ ~SingleOutput();
+
+ SingleOutput& operator =( const SingleOutput& copyobj );
+
+ void InitOutput();
+ virtual int WriteOutputFile();
+
+protected:
+ BspObject* m_baseobject;
+ FileAccess m_output;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _SINGLEOUTPUT_H_
+
diff --git a/tool_src/BspLib/SystemIO.cpp b/tool_src/BspLib/SystemIO.cpp
new file mode 100644
index 0000000..f5e1be6
--- /dev/null
+++ b/tool_src/BspLib/SystemIO.cpp
@@ -0,0 +1,314 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: SystemIO.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// define bsplib version string -----------------------------------------------
+//
+#define BSPLIB_VERSION "1.48"
+
+
+// set program's name which is an optional part of error messages -------------
+//
+void SystemIO::SetProgramName( const char *name )
+{
+ program_name = name;
+}
+
+
+// set callback for info message output function ------------------------------
+//
+void SystemIO::SetInfoMessageCallback( void (*callb)(const char*) )
+{
+ infomessage_callback = callb;
+}
+
+
+// set callback for error message output function -----------------------------
+//
+void SystemIO::SetErrorMessageCallback( void (*callb)(const char*) )
+{
+ errormessage_callback = callb;
+}
+
+
+// set callback for critical error handler ------------------------------------
+//
+void SystemIO::SetCriticalErrorCallback( int (*callb)(int) )
+{
+ criticalerror_callback = callb;
+}
+
+
+// display informational message (system dependent code encapsulated here) ----
+//
+void SystemIO::InfoMessage( const char *message )
+{
+ if ( infomessage_callback != NULL ) {
+ // call user supplied handler function
+ infomessage_callback( message );
+
+ } else {
+
+#if defined( _WINDOWS ) || defined( WIN32 )
+ MessageBox( hwnd_main, message, "BspLib Info", MB_OK | MB_ICONINFORMATION );
+#else
+ printf( "%s", message );
+ fflush( stdout );
+#endif
+
+ }
+}
+
+
+// display error message (system dependent code encapsulated here) ------------
+//
+void SystemIO::ErrorMessage( const char *message )
+{
+ if ( errormessage_callback != NULL ) {
+ // call user supplied handler function
+ errormessage_callback( message );
+
+ } else {
+
+#if defined( _WINDOWS ) || defined( WIN32 )
+ MessageBox( hwnd_main, message, "BspLib Error", MB_OK | MB_ICONERROR );
+#else
+ fflush( stdout );
+ fprintf( stderr, "%s: %s\n", program_name, message );
+ fflush( stderr );
+#endif
+
+ }
+}
+
+
+// reaction to critical error -------------------------------------------------
+//
+void SystemIO::HandleCriticalError( int flags )
+{
+ int handled = 0;
+ if ( criticalerror_callback != NULL ) {
+ // give user a chance to handle critical error
+ handled = criticalerror_callback( flags );
+ }
+ // if user failed to handle error exit from program
+ if ( !handled || ( ( flags & CRITERR_ALLOW_RET ) == 0 ) )
+ exit( EXIT_FAILURE );
+}
+
+
+// open file via FileAccess (resource acquisition is initialization) ----------
+//
+SystemIO::FileAccess::FileAccess( const char *fname, const char *mode, int flags )
+ : SystemIO::FilePtr( fname, mode )
+{
+ filename = new char[ strlen( fname ) + 1 ];
+ strcpy( filename, fname );
+
+ status = ( fp != NULL ) ? SYSTEM_IO_OK : FILE_NOT_FOUND;
+
+ if ( ( flags & CHECK_ERRORS ) && ( status != SYSTEM_IO_OK ) )
+ IOError( status );
+}
+
+
+// close FileAccess (resource acquisition is initialization) ------------------
+//
+SystemIO::FileAccess::~FileAccess()
+{
+ delete filename;
+}
+
+
+// reopen file ----------------------------------------------------------------
+//
+int SystemIO::FileAccess::ReOpen( const char *fname, const char *mode, int flags )
+{
+ if ( status == FILE_CLOSED ) {
+ status = ( fopen( fname, mode ) != NULL ) ? SYSTEM_IO_OK : FILE_NOT_FOUND;
+
+ if ( ( flags & CHECK_ERRORS ) && ( status != SYSTEM_IO_OK ) )
+ IOError( status );
+ return status;
+ } else {
+ return FILE_ALREADY_OPEN;
+ }
+}
+
+
+// close file -----------------------------------------------------------------
+//
+int SystemIO::FileAccess::Close()
+{
+ status = ( fclose( fp ) == 0 ) ? FILE_CLOSED : SYSTEM_IO_ERROR;
+ return ( status == FILE_CLOSED );
+}
+
+
+// read from file -------------------------------------------------------------
+//
+int SystemIO::FileAccess::Read( void *buffer, size_t size, size_t count, int flags )
+{
+ if ( status == SYSTEM_IO_OK ) {
+ if ( fread( buffer, size, count, fp ) == count )
+ status = SYSTEM_IO_OK;
+ else
+ status = feof( fp ) ? END_OF_FILE : FILE_READ_ERROR;
+
+ if ( ( flags & CHECK_ERRORS ) && ( status != SYSTEM_IO_OK ) )
+ IOError( status );
+ } else {
+ if ( flags & CHECK_ERRORS ) IOError( status );
+ }
+
+ return status;
+}
+
+
+// write to file --------------------------------------------------------------
+//
+int SystemIO::FileAccess::Write( void *buffer, size_t size, size_t count, int flags )
+{
+ if ( status == SYSTEM_IO_OK ) {
+ status = ( fwrite( buffer, size, count, fp ) == count ) ? SYSTEM_IO_OK : FILE_WRITE_ERROR;
+
+ if ( ( flags & CHECK_ERRORS ) && ( status != SYSTEM_IO_OK ) )
+ IOError( status );
+ } else {
+ if ( flags & CHECK_ERRORS ) IOError( status );
+ }
+
+ return status;
+}
+
+
+// read text line from file ---------------------------------------------------
+//
+char *SystemIO::FileAccess::ReadLine( char *line, int maxlen, int flags )
+{
+ if ( status == SYSTEM_IO_OK ) {
+ if ( fgets( line, maxlen, fp ) != NULL )
+ status = SYSTEM_IO_OK;
+ else
+ status = feof( fp ) ? END_OF_FILE : FILE_READ_ERROR;
+
+ if ( ( flags & CHECK_ERRORS ) && ( status != SYSTEM_IO_OK ) )
+ IOError( status );
+ return ( status == SYSTEM_IO_OK ) ? line : NULL;
+ } else {
+ if ( flags & CHECK_ERRORS ) IOError( status );
+ return NULL;
+ }
+}
+
+
+// write text line to file ----------------------------------------------------
+//
+const char *SystemIO::FileAccess::WriteLine( const char *line, int flags )
+{
+ if ( status == SYSTEM_IO_OK ) {
+ status = ( fprintf( fp, "%s", line ) != -1 ) ? SYSTEM_IO_OK : FILE_WRITE_ERROR;
+
+ if ( ( flags & CHECK_ERRORS ) && ( status != SYSTEM_IO_OK ) )
+ IOError( status );
+ return ( status == SYSTEM_IO_OK ) ? line : NULL;
+ } else {
+ if ( flags & CHECK_ERRORS ) IOError( status );
+ return NULL;
+ }
+}
+
+
+// I/O error handler ----------------------------------------------------------
+//
+void SystemIO::FileAccess::IOError( int errorcode )
+{
+ {
+ StrScratch errtext;
+ sprintf( errtext, "%s: %s", filename, strerror( errno ) );
+ ErrorMessage( errtext );
+ }
+ HandleCriticalError();
+}
+
+
+// construct String with init string ------------------------------------------
+//
+String::String( const char *src )
+{
+ if ( src != NULL ) {
+ data = new char[ strlen( src ) + 1 ];
+ strcpy( data, src );
+ } else {
+ data = NULL;
+ }
+}
+
+
+// copy constructor for String ------------------------------------------------
+//
+String::String( const String& copyobj )
+{
+ if ( copyobj.data != NULL ) {
+ data = new char[ strlen( copyobj.data ) + 1 ];
+ strcpy( data, copyobj.data );
+ } else {
+ data = NULL;
+ }
+}
+
+
+// assignment operator for String ---------------------------------------------
+//
+String& String::operator =( const String& copyobj )
+{
+ if ( &copyobj != this ) {
+ delete data;
+ if ( copyobj.data != NULL ) {
+ data = new char[ strlen( copyobj.data ) + 1 ];
+ strcpy( data, copyobj.data );
+ } else {
+ data = NULL;
+ }
+ }
+ return *this;
+}
+
+
+// pointer to global string containing the program's name ---------------------
+//
+const char *SystemIO::program_name = NULL;
+
+
+// pointers to user supplied callback functions -------------------------------
+//
+void (*SystemIO::infomessage_callback)(const char*) = NULL;
+void (*SystemIO::errormessage_callback)(const char*) = NULL;
+int (*SystemIO::criticalerror_callback)(int) = NULL;
+
+
+// handle of main window (used only when system is Win32) ---------------------
+//
+#if defined( _WINDOWS ) || defined( WIN32 )
+HWND SystemIO::hwnd_main = NULL;
+#endif
+
+
+// bsplib version string ------------------------------------------------------
+//
+const char SystemIO::version_str[] = BSPLIB_VERSION;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/SystemIO.h b/tool_src/BspLib/SystemIO.h
new file mode 100644
index 0000000..536ebf9
--- /dev/null
+++ b/tool_src/BspLib/SystemIO.h
@@ -0,0 +1,172 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: SystemIO.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _SYSTEMIO_H_
+#define _SYSTEMIO_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+
+// windows header files
+#if defined( _WINDOWS ) || defined( WIN32 )
+#include "windows.h"
+#endif
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// system specific I/O class; virtual base of all I/O capable classes ---------
+//
+class SystemIO {
+
+public:
+
+ // possible status codes
+ enum {
+ SYSTEM_IO_OK = 0x0000,
+ SYSTEM_IO_ERROR = 0x0001,
+ END_OF_FILE = 0x0002,
+ FILE_NOT_FOUND = 0x0003,
+ FILE_READ_ERROR = 0x0004,
+ FILE_WRITE_ERROR = 0x0005,
+ FILE_CLOSED = 0x0006,
+ FILE_ALREADY_OPEN = 0x0007,
+ };
+
+ // error action flags for critical error handling
+ enum {
+ CRITERR_ALLOW_RET = 0x0001,
+ };
+
+ // error action flags for file access
+ enum {
+ CHECK_ERRORS = 0x0001,
+ };
+
+public:
+ static void InfoMessage( const char *message );
+ static void ErrorMessage( const char *message );
+ static void HandleCriticalError( int flags = 0 );
+ static void SetProgramName( const char *name );
+ static void SetInfoMessageCallback( void (*callb)(const char*) );
+ static void SetErrorMessageCallback( void (*callb)(const char*) );
+ static void SetCriticalErrorCallback( int (*callb)(int) );
+
+#if defined( _WINDOWS ) || defined( WIN32 )
+ static void SetMainWindowHandle( HWND hwnd ) { hwnd_main = hwnd; }
+#endif
+
+public:
+ static const char version_str[];
+
+private:
+ static const char *program_name;
+ static void (*infomessage_callback)(const char*);
+ static void (*errormessage_callback)(const char*);
+ static int (*criticalerror_callback)(int);
+
+#if defined( _WINDOWS ) || defined( WIN32 )
+ static HWND hwnd_main;
+#endif
+
+
+protected:
+
+
+// file ptr class supporting "resource acquisition is initialization" ----
+class FilePtr {
+
+public:
+ FilePtr( const char *fname, const char *mode ) { fp = fopen( fname, mode ); }
+ ~FilePtr() { if ( fp ) fclose( fp ); }
+
+ operator FILE*() { return fp; }
+
+protected:
+ FILE *fp;
+
+}; // class SystemIO::FilePtr
+
+
+// augmented FilePtr -----------------------------------------------------
+class FileAccess : public FilePtr {
+
+public:
+ FileAccess( const char *fname, const char *mode, int flags = CHECK_ERRORS );
+ ~FileAccess();
+
+ int ReOpen( const char *fname, const char *mode, int flags = CHECK_ERRORS );
+ int Close();
+
+ int Read( void *buffer, size_t size, size_t count, int flags = 0 );
+ int Write( void *buffer, size_t size, size_t count, int flags = 0 );
+
+ char *ReadLine( char *line, int maxlen, int flags = 0 );
+ const char *WriteLine( const char *line, int flags = 0 );
+
+ int Status() { return status; }
+
+ char *getFileName() { return filename; }
+
+private:
+ void IOError( int errorcode );
+
+private:
+ char *filename;
+ int status;
+
+}; // class SystemIO::FileAccess
+
+
+// string scratch pad ----------------------------------------------------
+class StrScratch {
+
+public:
+ StrScratch() { line = new char[ 1024 ]; }
+ ~StrScratch() { delete line; }
+
+ operator char*() { return line; }
+
+private:
+ char *line;
+
+}; // class SystemIO::StrScratch
+
+
+}; // class SystemIO
+
+
+// quick and dirty string class -----------------------------------------------
+//
+class String {
+
+public:
+ String() { data = NULL; }
+ String( const char *src );
+ ~String() { delete data; }
+
+ String( const String& copyobj );
+ String& operator =( const String& copyobj );
+
+ operator char*() { return data; }
+
+ int IsNULL() const { return ( data == NULL ); }
+ int IsEmpty() const { return data ? ( *data == '\0' ) : TRUE; }
+
+ int getLength() const { return data ? strlen( data ) : 0; }
+
+private:
+ char *data;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _SYSTEMIO_H_
+
diff --git a/tool_src/BspLib/Texture.cpp b/tool_src/BspLib/Texture.cpp
new file mode 100644
index 0000000..16fc494
--- /dev/null
+++ b/tool_src/BspLib/Texture.cpp
@@ -0,0 +1,77 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Texture.cpp
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Texture.h"
+#include "Chunk.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// write texture information to text file -------------------------------------
+//
+void Texture::WriteInfo( FILE *fp )
+{
+ fprintf( fp, "%d/%d\t\t\"%s\"\t\t%s\n", m_width, m_height, m_name, m_file );
+}
+
+
+// constructor for Texture ----------------------------------------------------
+//
+Texture::Texture( int w, int h, char *tname, char *fname )
+{
+ *m_name = 0;
+ *m_file = 0;
+
+ if ( tname != NULL ) {
+ setName( tname );
+ }
+
+ if ( fname != NULL ) {
+ setFile( fname );
+ }
+
+ m_width = w;
+ m_height = h;
+}
+
+
+// set name of texture --------------------------------------------------------
+//
+void Texture::setName( const char *tname )
+{
+ if ( tname != NULL ) {
+ strncpy( m_name, tname, MAX_TEXNAME );
+ m_name[ MAX_TEXNAME ] = 0;
+ } else {
+ *m_name = 0;
+ }
+}
+
+
+// set filename of texture data file ------------------------------------------
+//
+void Texture::setFile( const char *fname )
+{
+ if ( fname != NULL ) {
+ strncpy( m_file, fname, PATH_MAX );
+ m_file[ PATH_MAX ] = 0;
+ } else {
+ *m_file = 0;
+ }
+}
+
+
+// size of texture chunk ------------------------------------------------------
+//
+template <> const int ChunkRep<Texture>::CHUNK_SIZE = 128;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Texture.h b/tool_src/BspLib/Texture.h
new file mode 100644
index 0000000..cbea4fe
--- /dev/null
+++ b/tool_src/BspLib/Texture.h
@@ -0,0 +1,58 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Texture.h
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _TEXTURE_H_
+#define _TEXTURE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Chunk.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+#define MAX_TEXNAME 31
+
+
+// class Texture; file oriented, only used for descriptive purposes -----------
+//
+class Texture : public virtual SystemIO {
+
+public:
+ Texture( int w = -1, int h = -1, char *tname = NULL, char *fname = NULL );
+ ~Texture() { }
+
+ int getWidth() const { return m_width; }
+ int getHeight() const { return m_height; }
+ const char* getName() const { return m_name; }
+ const char* getFile() const { return m_file; }
+
+ void setWidth( int w ) { m_width = w; }
+ void setHeight( int h ) { m_height = h; }
+ void setName( const char *tname );
+ void setFile( const char *fname );
+
+ void WriteInfo( FILE *fp );
+
+private:
+ int m_width;
+ int m_height;
+ char m_name[ MAX_TEXNAME + 1 ];
+ char m_file[ PATH_MAX + 1 ];
+};
+
+// typedef chunk of textures --------------------------------------------------
+typedef Chunk<Texture> TextureChunk;
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _TEXTURE_H_
+
diff --git a/tool_src/BspLib/Transform2.cpp b/tool_src/BspLib/Transform2.cpp
new file mode 100644
index 0000000..5d6a48b
--- /dev/null
+++ b/tool_src/BspLib/Transform2.cpp
@@ -0,0 +1,282 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Transform2.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Transform2.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// multiply two 3x3 matrices --------------------------------------------------
+//
+PRIVATE
+void mat3x3_mul( double dest_matrix[][3], const double matrix1[][3], const double matrix2[][3] )
+{
+ //NOTE:
+ // full homogeneous multiplication is performed. (that is, all 9
+ // elements are calculated.) normally this isn't necessary as
+ // most matrices are affine. but since this is no real-time
+ // application more flexibility seems better.
+/*
+ for ( int i = 0; i < 3; i++ ) {
+ for ( int j = 0; j < 3; j++ ) {
+ dest_matrix[ i ][ j ] = 0.0;
+ for ( int k = 0; k < 3; k++ )
+ dest_matrix[ i ][ j ] += matrix1[ i ][ k ] * matrix2[ k ][ j ];
+ }
+ }
+*/
+ dest_matrix[ 0 ][ 0 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 0 ];
+ dest_matrix[ 0 ][ 1 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 1 ];
+ dest_matrix[ 0 ][ 2 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 2 ];
+
+ dest_matrix[ 1 ][ 0 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 0 ];
+ dest_matrix[ 1 ][ 1 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 1 ];
+ dest_matrix[ 1 ][ 2 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 2 ];
+
+ dest_matrix[ 2 ][ 0 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 0 ];
+ dest_matrix[ 2 ][ 1 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 1 ];
+ dest_matrix[ 2 ][ 2 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 2 ];
+}
+
+
+// calculate concatenation; don't overwrite object matrix ---------------------
+//
+Transform2 operator *( const Transform2& trafo1, const Transform2& trafo2 )
+{
+ Transform2 temp;
+ mat3x3_mul( temp.m_matrix, trafo1.m_matrix, trafo2.m_matrix );
+ return temp;
+}
+
+
+// calculate concatenation as new object matrix -------------------------------
+//
+Transform2& Transform2::Concat( const Transform2& cattrafo )
+{
+ Transform2 temp;
+ mat3x3_mul( temp.m_matrix, (const double(*)[3]) m_matrix, cattrafo.m_matrix );
+ memcpy( m_matrix, temp.m_matrix, sizeof( m_matrix ) );
+ return *this;
+}
+
+
+// reversed concatenation -----------------------------------------------------
+//
+Transform2& Transform2::ConcatR( const Transform2& cattrafo )
+{
+ Transform2 temp;
+ mat3x3_mul( temp.m_matrix, cattrafo.m_matrix, (const double(*)[3]) m_matrix );
+ memcpy( m_matrix, temp.m_matrix, sizeof( m_matrix ) );
+ return *this;
+}
+
+
+// transform Vector2 by matrix (homogeneous component is also evaluated!) -----
+//
+Vector2 Transform2::TransformVector2( const Vector2& vec ) const
+{
+ Vector2 temp;
+ temp.setX( m_matrix[ 0 ][ 0 ] * vec.getX() + m_matrix[ 1 ][ 0 ] * vec.getY() + m_matrix[ 2 ][ 0 ] * vec.getW() );
+ temp.setY( m_matrix[ 0 ][ 1 ] * vec.getX() + m_matrix[ 1 ][ 1 ] * vec.getY() + m_matrix[ 2 ][ 1 ] * vec.getW() );
+ temp.setW( m_matrix[ 0 ][ 2 ] * vec.getX() + m_matrix[ 1 ][ 2 ] * vec.getY() + m_matrix[ 2 ][ 2 ] * vec.getW() );
+ return temp;
+}
+
+
+// calc determinant of matrix -------------------------------------------------
+//
+double Transform2::Determinant()
+{
+ // calc determinant using rule of sarrus
+ double pos;
+ pos = m_matrix[ 0 ][ 0 ] * m_matrix[ 1 ][ 1 ] * m_matrix[ 2 ][ 2 ];
+ pos += m_matrix[ 0 ][ 1 ] * m_matrix[ 1 ][ 2 ] * m_matrix[ 2 ][ 0 ];
+ pos += m_matrix[ 0 ][ 2 ] * m_matrix[ 1 ][ 0 ] * m_matrix[ 2 ][ 1 ];
+ double neg;
+ neg = m_matrix[ 0 ][ 0 ] * m_matrix[ 1 ][ 2 ] * m_matrix[ 2 ][ 1 ];
+ neg += m_matrix[ 0 ][ 1 ] * m_matrix[ 1 ][ 0 ] * m_matrix[ 2 ][ 2 ];
+ neg += m_matrix[ 0 ][ 2 ] * m_matrix[ 1 ][ 1 ] * m_matrix[ 2 ][ 0 ];
+
+ return ( pos - neg );
+}
+
+
+// calc matrix inverse --------------------------------------------------------
+//
+int Transform2::Inverse( Transform2& inverse )
+{
+ // calculate determinant
+ double det = Determinant();
+ // check for singularity
+ if ( fabs( det ) < EPS_DENOM_ZERO )
+ return 0;
+
+ // calculate inverse
+ double detinv = 1 / det;
+ inverse.m_matrix[ 0 ][ 0 ] = ( m_matrix[ 1 ][ 1 ] * m_matrix[ 2 ][ 2 ] - m_matrix[ 1 ][ 2 ] * m_matrix[ 2 ][ 1 ] ) * detinv;
+ inverse.m_matrix[ 0 ][ 1 ] = ( m_matrix[ 0 ][ 2 ] * m_matrix[ 2 ][ 1 ] - m_matrix[ 0 ][ 1 ] * m_matrix[ 2 ][ 2 ] ) * detinv;
+ inverse.m_matrix[ 0 ][ 2 ] = ( m_matrix[ 0 ][ 1 ] * m_matrix[ 1 ][ 2 ] - m_matrix[ 0 ][ 2 ] * m_matrix[ 1 ][ 1 ] ) * detinv;
+ inverse.m_matrix[ 1 ][ 0 ] = ( m_matrix[ 1 ][ 2 ] * m_matrix[ 2 ][ 0 ] - m_matrix[ 1 ][ 0 ] * m_matrix[ 2 ][ 2 ] ) * detinv;
+ inverse.m_matrix[ 1 ][ 1 ] = ( m_matrix[ 0 ][ 0 ] * m_matrix[ 2 ][ 2 ] - m_matrix[ 0 ][ 2 ] * m_matrix[ 2 ][ 0 ] ) * detinv;
+ inverse.m_matrix[ 1 ][ 2 ] = ( m_matrix[ 0 ][ 2 ] * m_matrix[ 1 ][ 0 ] - m_matrix[ 0 ][ 0 ] * m_matrix[ 1 ][ 2 ] ) * detinv;
+ inverse.m_matrix[ 2 ][ 0 ] = ( m_matrix[ 1 ][ 0 ] * m_matrix[ 2 ][ 1 ] - m_matrix[ 1 ][ 1 ] * m_matrix[ 2 ][ 0 ] ) * detinv;
+ inverse.m_matrix[ 2 ][ 1 ] = ( m_matrix[ 0 ][ 1 ] * m_matrix[ 2 ][ 0 ] - m_matrix[ 0 ][ 0 ] * m_matrix[ 2 ][ 1 ] ) * detinv;
+ inverse.m_matrix[ 2 ][ 2 ] = ( m_matrix[ 0 ][ 0 ] * m_matrix[ 1 ][ 1 ] - m_matrix[ 0 ][ 1 ] * m_matrix[ 1 ][ 0 ] ) * detinv;
+
+ return 1;
+}
+
+
+// fetch translation part of matrix -------------------------------------------
+//
+Vector2 Transform2::FetchTranslation() const
+{
+ // return translation vector
+ return Vector2( m_matrix[ 2 ][ 0 ], m_matrix[ 2 ][ 1 ] );
+}
+
+
+// extract translation part of matrix; set to NULL translation afterwards -----
+//
+Vector2 Transform2::ExtractTranslation()
+{
+ // create translation vector
+ Vector2 temp( m_matrix[ 2 ][ 0 ], m_matrix[ 2 ][ 1 ] );
+ // zero translation part of matrix
+ m_matrix[ 2 ][ 0 ] = 0.0;
+ m_matrix[ 2 ][ 1 ] = 0.0;
+ return temp;
+}
+
+
+// create rotation matrix -----------------------------------------------------
+//
+Transform2& Transform2::LoadRotation( double angle )
+{
+ // init matrix
+ LoadIdentity();
+
+ // set rotated basis
+ m_matrix[ 0 ][ 0 ] = cos( angle );
+ m_matrix[ 0 ][ 1 ] = sin( angle );
+ m_matrix[ 1 ][ 0 ] = -m_matrix[ 0 ][ 1 ];
+ m_matrix[ 1 ][ 1 ] = m_matrix[ 0 ][ 0 ];
+
+ return *this;
+}
+
+
+// create scale matrix --------------------------------------------------------
+//
+Transform2& Transform2::LoadScale( double x, double y )
+{
+ LoadIdentity();
+ m_matrix[ 0 ][ 0 ] = x;
+ m_matrix[ 1 ][ 1 ] = y;
+ return *this;
+}
+
+
+// create translation matrix --------------------------------------------------
+//
+Transform2& Transform2::LoadTranslation( double x, double y )
+{
+ LoadIdentity();
+ m_matrix[ 2 ][ 0 ] = x;
+ m_matrix[ 2 ][ 1 ] = y;
+ return *this;
+}
+
+
+// rotate around arbitrary axis -----------------------------------------------
+//
+Transform2& Transform2::Rotate( double angle )
+{
+ Transform2 temp;
+ temp.LoadRotation( angle );
+ Concat( temp );
+ return *this;
+}
+
+
+// rotate around arbitrary axis (reversed) ------------------------------------
+//
+Transform2& Transform2::RotateR( double angle )
+{
+ Transform2 temp;
+ temp.LoadRotation( angle );
+ ConcatR( temp );
+ return *this;
+}
+
+
+// apply scale factors --------------------------------------------------------
+//
+Transform2& Transform2::Scale( double x, double y )
+{
+ Transform2 temp;
+ temp.LoadScale( x, y );
+ Concat( temp );
+ return *this;
+}
+
+
+// apply scale factors (reversed) ---------------------------------------------
+//
+Transform2& Transform2::ScaleR( double x, double y )
+{
+ Transform2 temp;
+ temp.LoadScale( x, y );
+ ConcatR( temp );
+ return *this;
+}
+
+
+// apply translation ----------------------------------------------------------
+//
+Transform2& Transform2::Translate( double x, double y )
+{
+ m_matrix[ 2 ][ 0 ] += x;
+ m_matrix[ 2 ][ 1 ] += y;
+ return *this;
+}
+
+
+// apply translation (reversed) -----------------------------------------------
+//
+Transform2& Transform2::TranslateR( double x, double y )
+{
+ Transform2 temp;
+ temp.LoadTranslation( x, y );
+ ConcatR( temp );
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Transform2.h b/tool_src/BspLib/Transform2.h
new file mode 100644
index 0000000..b5785ab
--- /dev/null
+++ b/tool_src/BspLib/Transform2.h
@@ -0,0 +1,111 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Transform2.h
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _TRANSFORM2_H_
+#define _TRANSFORM2_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// general 2-D homogeneous transformation -------------------------------------
+//
+class Transform2 {
+
+ friend Transform2 operator *( const Transform2& trafo1, const Transform2& trafo2 );
+
+public:
+ Transform2();
+ Transform2( const float trafo[3][3] );
+ Transform2( const double trafo[3][3] );
+ ~Transform2() { }
+
+ // transform single vector by current transformation
+ Vector2 TransformVector2( const Vector2& vec ) const;
+
+ double Determinant(); // calc matrix's determinant
+ int Inverse( Transform2& inverse ); // calc matrix's inverse
+
+ // concatenate two transformations (natural and reversed order)
+ Transform2& Concat( const Transform2& cattrafo );
+ Transform2& ConcatR( const Transform2& cattrafo );
+
+ // create elementary matrices
+ Transform2& LoadIdentity();
+ Transform2& LoadRotation( double angle );
+ Transform2& LoadScale( double x, double y );
+ Transform2& LoadTranslation( double x, double y );
+
+ // elementary transformations in natural order
+ Transform2& Rotate( double angle );
+ Transform2& Scale( double x, double y );
+ Transform2& Translate( double x, double y );
+
+ // elementary transformations in reversed order
+ Transform2& RotateR( double angle );
+ Transform2& ScaleR( double x, double y );
+ Transform2& TranslateR( double x, double y );
+
+ // fetch translation part (optionally set it null afterwards)
+ Vector2 FetchTranslation() const;
+ Vector2 ExtractTranslation();
+
+ // fetch pointer to matrix
+ double * LinMatrixAccess() { return (double *) m_matrix; }
+
+private:
+ // 3x3 matrix for 2-D homogeneous transformation (row vectors!)
+ double m_matrix[3][3];
+};
+
+// load identity matrix -------------------------------------------------------
+inline Transform2& Transform2::LoadIdentity()
+{
+ memset( m_matrix, 0, sizeof( m_matrix ) );
+
+ m_matrix[ 0 ][ 0 ] = 1.0;
+ m_matrix[ 1 ][ 1 ] = 1.0;
+ m_matrix[ 2 ][ 2 ] = 1.0;
+
+ return *this;
+}
+
+// construct a Transform2 -----------------------------------------------------
+inline Transform2::Transform2()
+{
+// LoadIdentity();
+}
+
+// construct a Transform2 directly from 3x3 matrix ----------------------------
+inline Transform2::Transform2( const double trafo[3][3] )
+{
+ //CAVEAT:
+ // the outer dimension of the matrix is not enforced!!
+ // trafo is actually of type double(*)[3]
+ memcpy( m_matrix, trafo, sizeof( m_matrix ) );
+}
+
+// construct a Transform2 directly from 3x3 matrix ----------------------------
+inline Transform2::Transform2( const float trafo[3][3] )
+{
+ //CAVEAT:
+ // the outer dimension of the matrix is not enforced!!
+ // trafo is actually of type float(*)[3]
+ for ( int i = 0; i < 9; i++ )
+ ((double *)m_matrix)[ i ] = (double) ((float *)trafo)[ i ];
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _TRANSFORM2_H_
+
diff --git a/tool_src/BspLib/Transform3.cpp b/tool_src/BspLib/Transform3.cpp
new file mode 100644
index 0000000..7f8b54d
--- /dev/null
+++ b/tool_src/BspLib/Transform3.cpp
@@ -0,0 +1,312 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Transform3.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Transform3.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// multiply two 4x4 matrices --------------------------------------------------
+//
+PRIVATE
+void mat4x4_mul( double dest_matrix[][4], const double matrix1[][4], const double matrix2[][4] )
+{
+ //NOTE:
+ // full homogeneous multiplication is performed. (that is, all 16
+ // elements are calculated.) normally this isn't necessary as
+ // most matrices are affine. but since this is no real-time
+ // application more flexibility seems better.
+/*
+ for ( int i = 0; i < 4; i++ ) {
+ for ( int j = 0; j < 4; j++ ) {
+ dest_matrix[ i ][ j ] = 0.0;
+ for ( int k = 0; k < 4; k++ )
+ dest_matrix[ i ][ j ] += matrix1[ i ][ k ] * matrix2[ k ][ j ];
+ }
+ }
+*/
+ dest_matrix[ 0 ][ 0 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 0 ] +
+ matrix1[ 0 ][ 3 ] * matrix2[ 3 ][ 0 ];
+ dest_matrix[ 0 ][ 1 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 1 ] +
+ matrix1[ 0 ][ 3 ] * matrix2[ 3 ][ 1 ];
+ dest_matrix[ 0 ][ 2 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 2 ] +
+ matrix1[ 0 ][ 3 ] * matrix2[ 3 ][ 2 ];
+ dest_matrix[ 0 ][ 3 ] = matrix1[ 0 ][ 0 ] * matrix2[ 0 ][ 3 ] +
+ matrix1[ 0 ][ 1 ] * matrix2[ 1 ][ 3 ] +
+ matrix1[ 0 ][ 2 ] * matrix2[ 2 ][ 3 ] +
+ matrix1[ 0 ][ 3 ] * matrix2[ 3 ][ 3 ];
+
+ dest_matrix[ 1 ][ 0 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 0 ] +
+ matrix1[ 1 ][ 3 ] * matrix2[ 3 ][ 0 ];
+ dest_matrix[ 1 ][ 1 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 1 ] +
+ matrix1[ 1 ][ 3 ] * matrix2[ 3 ][ 1 ];
+ dest_matrix[ 1 ][ 2 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 2 ] +
+ matrix1[ 1 ][ 3 ] * matrix2[ 3 ][ 2 ];
+ dest_matrix[ 1 ][ 3 ] = matrix1[ 1 ][ 0 ] * matrix2[ 0 ][ 3 ] +
+ matrix1[ 1 ][ 1 ] * matrix2[ 1 ][ 3 ] +
+ matrix1[ 1 ][ 2 ] * matrix2[ 2 ][ 3 ] +
+ matrix1[ 1 ][ 3 ] * matrix2[ 3 ][ 3 ];
+
+ dest_matrix[ 2 ][ 0 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 0 ] +
+ matrix1[ 2 ][ 3 ] * matrix2[ 3 ][ 0 ];
+ dest_matrix[ 2 ][ 1 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 1 ] +
+ matrix1[ 2 ][ 3 ] * matrix2[ 3 ][ 1 ];
+ dest_matrix[ 2 ][ 2 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 2 ] +
+ matrix1[ 2 ][ 3 ] * matrix2[ 3 ][ 2 ];
+ dest_matrix[ 2 ][ 3 ] = matrix1[ 2 ][ 0 ] * matrix2[ 0 ][ 3 ] +
+ matrix1[ 2 ][ 1 ] * matrix2[ 1 ][ 3 ] +
+ matrix1[ 2 ][ 2 ] * matrix2[ 2 ][ 3 ] +
+ matrix1[ 2 ][ 3 ] * matrix2[ 3 ][ 3 ];
+
+ dest_matrix[ 3 ][ 0 ] = matrix1[ 3 ][ 0 ] * matrix2[ 0 ][ 0 ] +
+ matrix1[ 3 ][ 1 ] * matrix2[ 1 ][ 0 ] +
+ matrix1[ 3 ][ 2 ] * matrix2[ 2 ][ 0 ] +
+ matrix1[ 3 ][ 3 ] * matrix2[ 3 ][ 0 ];
+ dest_matrix[ 3 ][ 1 ] = matrix1[ 3 ][ 0 ] * matrix2[ 0 ][ 1 ] +
+ matrix1[ 3 ][ 1 ] * matrix2[ 1 ][ 1 ] +
+ matrix1[ 3 ][ 2 ] * matrix2[ 2 ][ 1 ] +
+ matrix1[ 3 ][ 3 ] * matrix2[ 3 ][ 1 ];
+ dest_matrix[ 3 ][ 2 ] = matrix1[ 3 ][ 0 ] * matrix2[ 0 ][ 2 ] +
+ matrix1[ 3 ][ 1 ] * matrix2[ 1 ][ 2 ] +
+ matrix1[ 3 ][ 2 ] * matrix2[ 2 ][ 2 ] +
+ matrix1[ 3 ][ 3 ] * matrix2[ 3 ][ 2 ];
+ dest_matrix[ 3 ][ 3 ] = matrix1[ 3 ][ 0 ] * matrix2[ 0 ][ 3 ] +
+ matrix1[ 3 ][ 1 ] * matrix2[ 1 ][ 3 ] +
+ matrix1[ 3 ][ 2 ] * matrix2[ 2 ][ 3 ] +
+ matrix1[ 3 ][ 3 ] * matrix2[ 3 ][ 3 ];
+}
+
+
+// calculate concatenation; don't overwrite object matrix ---------------------
+//
+Transform3 operator *( const Transform3& trafo1, const Transform3& trafo2 )
+{
+ Transform3 temp;
+ mat4x4_mul( temp.m_matrix, trafo1.m_matrix, trafo2.m_matrix );
+ return temp;
+}
+
+
+// calculate concatenation as new object matrix -------------------------------
+//
+Transform3& Transform3::Concat( const Transform3& cattrafo )
+{
+ Transform3 temp;
+ mat4x4_mul( temp.m_matrix, (const double(*)[4]) m_matrix, cattrafo.m_matrix );
+ memcpy( m_matrix, temp.m_matrix, sizeof( m_matrix ) );
+ return *this;
+}
+
+
+// reversed concatenation -----------------------------------------------------
+//
+Transform3& Transform3::ConcatR( const Transform3& cattrafo )
+{
+ Transform3 temp;
+ mat4x4_mul( temp.m_matrix, cattrafo.m_matrix, (const double(*)[4]) m_matrix );
+ memcpy( m_matrix, temp.m_matrix, sizeof( m_matrix ) );
+ return *this;
+}
+
+
+// transform Vector3 by matrix (homogeneous component is also evaluated!) -----
+//
+Vector3 Transform3::TransformVector3( const Vector3& vec ) const
+{
+ Vector3 temp;
+ temp.setX( m_matrix[ 0 ][ 0 ] * vec.getX() + m_matrix[ 1 ][ 0 ] * vec.getY() + m_matrix[ 2 ][ 0 ] * vec.getZ() + m_matrix[ 3 ][ 0 ] * vec.getW() );
+ temp.setY( m_matrix[ 0 ][ 1 ] * vec.getX() + m_matrix[ 1 ][ 1 ] * vec.getY() + m_matrix[ 2 ][ 1 ] * vec.getZ() + m_matrix[ 3 ][ 1 ] * vec.getW() );
+ temp.setZ( m_matrix[ 0 ][ 2 ] * vec.getX() + m_matrix[ 1 ][ 2 ] * vec.getY() + m_matrix[ 2 ][ 2 ] * vec.getZ() + m_matrix[ 3 ][ 2 ] * vec.getW() );
+ temp.setW( m_matrix[ 0 ][ 3 ] * vec.getX() + m_matrix[ 1 ][ 3 ] * vec.getY() + m_matrix[ 2 ][ 3 ] * vec.getZ() + m_matrix[ 3 ][ 3 ] * vec.getW() );
+ return temp;
+}
+
+
+// fetch translation part of matrix -------------------------------------------
+//
+Vector3 Transform3::FetchTranslation() const
+{
+ // return translation vector
+ return Vector3( m_matrix[ 3 ][ 0 ], m_matrix[ 3 ][ 1 ], m_matrix[ 3 ][ 2 ] );
+}
+
+
+// extract translation part of matrix; set to NULL translation afterwards -----
+//
+Vector3 Transform3::ExtractTranslation()
+{
+ // create translation vector
+ Vector3 temp( m_matrix[ 3 ][ 0 ], m_matrix[ 3 ][ 1 ], m_matrix[ 3 ][ 2 ] );
+ // zero translation part of matrix
+ m_matrix[ 3 ][ 0 ] = 0.0;
+ m_matrix[ 3 ][ 1 ] = 0.0;
+ m_matrix[ 3 ][ 2 ] = 0.0;
+ return temp;
+}
+
+
+// create rotation matrix -----------------------------------------------------
+//
+Transform3& Transform3::LoadRotation( double angle, double x, double y, double z )
+{
+ // init matrix
+ LoadIdentity();
+
+ // normalize axis of rotation
+ Vector3 axis( x, y, z );
+ if ( !axis.Normalize() ) {
+ // NULL vector: return identity matrix
+ return *this;
+ }
+
+ // calculate unit quaternion corresponding to rotation
+ double phi2 = -angle / 2;
+ double sinphi2 = sin( phi2 );
+ double W = cos( phi2 );
+ double X = sinphi2 * axis.getX();
+ double Y = sinphi2 * axis.getY();
+ double Z = sinphi2 * axis.getZ();
+
+ // calculate intermediate terms
+ double X2 = X * X;
+ double Y2 = Y * Y;
+ double Z2 = Z * Z;
+ double XY = X * Y;
+ double XZ = X * Z;
+ double YZ = Y * Z;
+ double WX = W * X;
+ double WY = W * Y;
+ double WZ = W * Z;
+
+ // convert quaternion into rotation matrix
+ m_matrix[ 0 ][ 0 ] = 1 - ( Y2 + Z2 ) * 2;
+ m_matrix[ 0 ][ 1 ] = ( XY - WZ ) * 2;
+ m_matrix[ 0 ][ 2 ] = ( XZ + WY ) * 2;
+ m_matrix[ 1 ][ 0 ] = ( XY + WZ ) * 2;
+ m_matrix[ 1 ][ 1 ] = 1 - ( X2 + Z2 ) * 2;
+ m_matrix[ 1 ][ 2 ] = ( YZ - WX ) * 2;
+ m_matrix[ 2 ][ 0 ] = ( XZ - WY ) * 2;
+ m_matrix[ 2 ][ 1 ] = ( YZ + WX ) * 2;
+ m_matrix[ 2 ][ 2 ] = 1 - ( X2 + Y2 ) * 2;
+
+ return *this;
+}
+
+
+// create scale matrix --------------------------------------------------------
+//
+Transform3& Transform3::LoadScale( double x, double y, double z )
+{
+ LoadIdentity();
+ m_matrix[ 0 ][ 0 ] = x;
+ m_matrix[ 1 ][ 1 ] = y;
+ m_matrix[ 2 ][ 2 ] = z;
+ return *this;
+}
+
+
+// create translation matrix --------------------------------------------------
+//
+Transform3& Transform3::LoadTranslation( double x, double y, double z )
+{
+ LoadIdentity();
+ m_matrix[ 3 ][ 0 ] = x;
+ m_matrix[ 3 ][ 1 ] = y;
+ m_matrix[ 3 ][ 2 ] = z;
+ return *this;
+}
+
+
+// rotate around arbitrary axis -----------------------------------------------
+//
+Transform3& Transform3::Rotate( double angle, double x, double y, double z )
+{
+ Transform3 temp;
+ temp.LoadRotation( angle, x, y, z );
+ Concat( temp );
+ return *this;
+}
+
+
+// rotate around arbitrary axis (reversed) ------------------------------------
+//
+Transform3& Transform3::RotateR( double angle, double x, double y, double z )
+{
+ Transform3 temp;
+ temp.LoadRotation( angle, x, y, z );
+ ConcatR( temp );
+ return *this;
+}
+
+
+// apply scale factors --------------------------------------------------------
+//
+Transform3& Transform3::Scale( double x, double y, double z )
+{
+ Transform3 temp;
+ temp.LoadScale( x, y, z );
+ Concat( temp );
+ return *this;
+}
+
+
+// apply scale factors (reversed) ---------------------------------------------
+//
+Transform3& Transform3::ScaleR( double x, double y, double z )
+{
+ Transform3 temp;
+ temp.LoadScale( x, y, z );
+ ConcatR( temp );
+ return *this;
+}
+
+
+// apply translation ----------------------------------------------------------
+//
+Transform3& Transform3::Translate( double x, double y, double z )
+{
+ m_matrix[ 3 ][ 0 ] += x;
+ m_matrix[ 3 ][ 1 ] += y;
+ m_matrix[ 3 ][ 2 ] += z;
+ return *this;
+}
+
+
+// apply translation (reversed) -----------------------------------------------
+//
+Transform3& Transform3::TranslateR( double x, double y, double z )
+{
+ Transform3 temp;
+ temp.LoadTranslation( x, y, z );
+ ConcatR( temp );
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Transform3.h b/tool_src/BspLib/Transform3.h
new file mode 100644
index 0000000..58a1b7e
--- /dev/null
+++ b/tool_src/BspLib/Transform3.h
@@ -0,0 +1,106 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Transform3.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _TRANSFORM3_H_
+#define _TRANSFORM3_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// general 3-D homogeneous transformation -------------------------------------
+//
+class Transform3 {
+
+ friend Transform3 operator *( const Transform3& trafo1, const Transform3& trafo2 );
+
+public:
+ Transform3();
+ Transform3( const float trafo[4][4] );
+ Transform3( const double trafo[4][4] );
+ ~Transform3() { }
+
+ // transform single vector by current transformation
+ Vector3 TransformVector3( const Vector3& vec ) const;
+
+ // concatenate two transformations (natural and reversed order)
+ Transform3& Concat( const Transform3& cattrafo );
+ Transform3& ConcatR( const Transform3& cattrafo );
+
+ // create elementary matrices
+ Transform3& LoadIdentity();
+ Transform3& LoadRotation( double angle, double x, double y, double z );
+ Transform3& LoadScale( double x, double y, double z );
+ Transform3& LoadTranslation( double x, double y, double z );
+
+ // elementary transformations in natural order
+ Transform3& Rotate( double angle, double x, double y, double z );
+ Transform3& Scale( double x, double y, double z );
+ Transform3& Translate( double x, double y, double z );
+
+ // elementary transformations in reversed order
+ Transform3& RotateR( double angle, double x, double y, double z );
+ Transform3& ScaleR( double x, double y, double z );
+ Transform3& TranslateR( double x, double y, double z );
+
+ // fetch translation part (optionally set it null afterwards)
+ Vector3 FetchTranslation() const;
+ Vector3 ExtractTranslation();
+
+private:
+ // 4x4 matrix for 3-D homogeneous transformation (row vectors!)
+ double m_matrix[4][4];
+};
+
+// load identity matrix -------------------------------------------------------
+inline Transform3& Transform3::LoadIdentity()
+{
+ memset( m_matrix, 0, sizeof( m_matrix ) );
+
+ m_matrix[ 0 ][ 0 ] = 1.0;
+ m_matrix[ 1 ][ 1 ] = 1.0;
+ m_matrix[ 2 ][ 2 ] = 1.0;
+ m_matrix[ 3 ][ 3 ] = 1.0;
+
+ return *this;
+}
+
+// construct a transform3 -----------------------------------------------------
+inline Transform3::Transform3()
+{
+// LoadIdentity();
+}
+
+// construct a transform3 directly from 4x4 matrix ----------------------------
+inline Transform3::Transform3( const double trafo[4][4] )
+{
+ //CAVEAT:
+ // the outer dimension of the matrix is not enforced!!
+ // trafo is actually of type double(*)[4]
+ memcpy( m_matrix, trafo, sizeof( m_matrix ) );
+}
+
+// construct a transform3 directly from 4x4 matrix ----------------------------
+inline Transform3::Transform3( const float trafo[4][4] )
+{
+ //CAVEAT:
+ // the outer dimension of the matrix is not enforced!!
+ // trafo is actually of type float(*)[4]
+ for ( int i = 0; i < 16; i++ )
+ ((double *)m_matrix)[ i ] = (double) ((float *)trafo)[ i ];
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _TRANSFORM3_H_
+
diff --git a/tool_src/BspLib/TriMapping.cpp b/tool_src/BspLib/TriMapping.cpp
new file mode 100644
index 0000000..c2e2185
--- /dev/null
+++ b/tool_src/BspLib/TriMapping.cpp
@@ -0,0 +1,26 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: TriMapping.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "TriMapping.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// invalid index for mapping vertex -------------------------------------------
+//
+void TriMapping::Error() const
+{
+ ErrorMessage( "\n***ERROR*** Invalid index in BspLib::TriMapping." );
+ HandleCriticalError();
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/TriMapping.h b/tool_src/BspLib/TriMapping.h
new file mode 100644
index 0000000..896b147
--- /dev/null
+++ b/tool_src/BspLib/TriMapping.h
@@ -0,0 +1,43 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: TriMapping.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _TRIMAPPING_H_
+#define _TRIMAPPING_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// affine mapping specification for a triangle --------------------------------
+//
+class TriMapping : public virtual SystemIO {
+
+ void Error() const;
+
+public:
+ TriMapping() { }
+ ~TriMapping() { }
+
+ Vertex2& getMapXY( int indx ) { if ( indx > 2 ) Error(); return map_xy[ indx ]; }
+ Vertex2& getMapUV( int indx ) { if ( indx > 2 ) Error(); return map_uv[ indx ]; }
+
+private:
+ Vertex2 map_xy[ 3 ]; // mapping is specified via three
+ Vertex2 map_uv[ 3 ]; // point correspondences
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _TRIMAPPING_H_
+
diff --git a/tool_src/BspLib/Vector.h b/tool_src/BspLib/Vector.h
new file mode 100644
index 0000000..92f9bbe
--- /dev/null
+++ b/tool_src/BspLib/Vector.h
@@ -0,0 +1,100 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Vector.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VECTOR_H_
+#define _VECTOR_H_
+
+// bsplib header files
+#include "Vector3.h"
+#include "Vector2.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// vertex plus vector yields vertex -------------------------------------------
+inline Vertex3 operator +( const Vertex3 v1, const Vector3 v2 )
+{
+ return Vertex3( v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z, 1.0 );
+}
+
+// vector plus vertex yields vertex -------------------------------------------
+inline Vertex3 operator +( const Vector3 v1, const Vertex3 v2 )
+{
+ return Vertex3( v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z, 1.0 );
+}
+
+// vertex minus vertex yields vector ------------------------------------------
+inline Vector3 operator -( const Vertex3 v1, const Vertex3 v2 )
+{
+ return Vector3( v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z, 1.0 );
+}
+
+// vertex minus vector yields vertex ------------------------------------------
+inline Vertex3 operator -( const Vertex3 v1, const Vector3 v2 )
+{
+ return Vertex3( v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z, 1.0 );
+}
+
+// vector plus vector yields vector -------------------------------------------
+inline Vector3 operator +( const Vector3 v1, const Vector3 v2 )
+{
+ return Vector3( v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z, 1.0 );
+}
+
+// vector minus vector yields vector ------------------------------------------
+inline Vector3 operator -( const Vector3 v1, const Vector3 v2 )
+{
+ return Vector3( v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z, 1.0 );
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+// vertex plus vector yields vertex -------------------------------------------
+inline Vertex2 operator +( const Vertex2 v1, const Vector2 v2 )
+{
+ return Vertex2( v1.X + v2.X, v1.Y + v2.Y, 1.0 );
+}
+
+// vector plus vertex yields vertex -------------------------------------------
+inline Vertex2 operator +( const Vector2 v1, const Vertex2 v2 )
+{
+ return Vertex2( v1.X + v2.X, v1.Y + v2.Y, 1.0 );
+}
+
+// vertex minus vertex yields vector ------------------------------------------
+inline Vector2 operator -( const Vertex2 v1, const Vertex2 v2 )
+{
+ return Vector2( v1.X - v2.X, v1.Y - v2.Y, 1.0 );
+}
+
+// vertex minus vector yields vertex ------------------------------------------
+inline Vertex2 operator -( const Vertex2 v1, const Vector2 v2 )
+{
+ return Vertex2( v1.X - v2.X, v1.Y - v2.Y, 1.0 );
+}
+
+// vector plus vector yields vector -------------------------------------------
+inline Vector2 operator +( const Vector2 v1, const Vector2 v2 )
+{
+ return Vector2( v1.X + v2.X, v1.Y + v2.Y, 1.0 );
+}
+
+// vector minus vector yields vector ------------------------------------------
+inline Vector2 operator -( const Vector2 v1, const Vector2 v2 )
+{
+ return Vector2( v1.X - v2.X, v1.Y - v2.Y, 1.0 );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VECTOR_H_
+
diff --git a/tool_src/BspLib/Vector2.h b/tool_src/BspLib/Vector2.h
new file mode 100644
index 0000000..7b9f275
--- /dev/null
+++ b/tool_src/BspLib/Vector2.h
@@ -0,0 +1,113 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Vector2.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VECTOR2_H_
+#define _VECTOR2_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vertex2.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// vector times scalar (post-multiply) ----------------------------------------
+inline Vector2 operator *( const Vector2 v1, double t )
+{
+ return Vector2( v1.X * t, v1.Y * t, 1.0 );
+}
+
+// scalar times vector (pre-multiply) -----------------------------------------
+inline Vector2 operator *( double t, const Vector2 v1 )
+{
+ return Vector2( v1.X * t, v1.Y * t, 1.0 );
+}
+
+// operator '+=' does memberwise addition for (X,Y) ---------------------------
+inline Vector2& Vector2::operator +=( const Vector2 v )
+{
+ X += v.X;
+ Y += v.Y;
+ return *this;
+}
+
+// operator '-=' does memberwise subtraction for (X,Y) ------------------------
+inline Vector2& Vector2::operator -=( const Vector2 v )
+{
+ X -= v.X;
+ Y -= v.Y;
+ return *this;
+}
+
+// operator '*=' does multiplication with a scalar ----------------------------
+inline Vector2& Vector2::operator *=( double t )
+{
+ X *= t;
+ Y *= t;
+ return *this;
+}
+
+// normalize vector (homogeneous coordinate will be set to one) ---------------
+inline int Vector2::Normalize()
+{
+ if ( IsNullVector() )
+ return FALSE;
+
+ double oonorm = 1 / VecLength();
+ X = X * oonorm;
+ Y = Y * oonorm;
+ W = 1.0;
+ return TRUE;
+}
+
+// homogenize vector (divide by homogeneous coordinate) -----------------------
+inline int Vector2::Homogenize()
+{
+ if ( fabs( W ) < EPS_DENOM_ZERO )
+ return FALSE;
+
+ double oow = 1 / W;
+ X = X * oow;
+ Y = Y * oow;
+ W = 1.0;
+ return TRUE;
+}
+
+// check if vector has length zero (employs an epsilon area) ------------------
+inline int Vector2::IsNullVector() const
+{
+ // the epsilon area is employed componentwise, not for the length itself!
+ return ( ( fabs( X ) < EPS_COMP_ZERO ) && ( fabs( Y ) < EPS_COMP_ZERO ) );
+}
+
+// calculate length of two dimensional vector ---------------------------------
+inline hprec_t Vector2::VecLength() const
+{
+ return sqrt( X * X + Y * Y );
+}
+
+// calculate floating point scalar-product ------------------------------------
+inline hprec_t Vector2::DotProduct( const Vector2& vect ) const
+{
+ return ( vect.X * X ) + ( vect.Y * Y );
+}
+
+// calc vector directed from second vertex to first vertex --------------------
+inline void Vector2::CreateDirVec( const Vertex2& vertex1, const Vertex2& vertex2 )
+{
+ X = vertex2.X - vertex1.X;
+ Y = vertex2.Y - vertex1.Y;
+ W = 1.0;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VECTOR2_H_
+
diff --git a/tool_src/BspLib/Vector3.h b/tool_src/BspLib/Vector3.h
new file mode 100644
index 0000000..f2c34e0
--- /dev/null
+++ b/tool_src/BspLib/Vector3.h
@@ -0,0 +1,134 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Vector3.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VECTOR3_H_
+#define _VECTOR3_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "Vertex3.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// vector times scalar (post-multiply) ----------------------------------------
+inline Vector3 operator *( const Vector3 v1, double t )
+{
+ return Vector3( v1.X * t, v1.Y * t, v1.Z * t, 1.0 );
+}
+
+// scalar times vector (pre-multiply) -----------------------------------------
+inline Vector3 operator *( double t, const Vector3 v1 )
+{
+ return Vector3( v1.X * t, v1.Y * t, v1.Z * t, 1.0 );
+}
+
+// construct Vector3 as cross product of two other vectors --------------------
+inline Vector3::Vector3( const Vector3& v1, const Vector3& v2 )
+{
+ CrossProduct( v1, v2 );
+}
+
+// operator '+=' does memberwise addition for (X,Y,Z) -------------------------
+inline Vector3& Vector3::operator +=( const Vector3 v )
+{
+ X += v.X;
+ Y += v.Y;
+ Z += v.Z;
+ return *this;
+}
+
+// operator '-=' does memberwise subtraction for (X,Y,Z) ----------------------
+inline Vector3& Vector3::operator -=( const Vector3 v )
+{
+ X -= v.X;
+ Y -= v.Y;
+ Z -= v.Z;
+ return *this;
+}
+
+// operator '*=' does multiplication with a scalar ----------------------------
+inline Vector3& Vector3::operator *=( double t )
+{
+ X *= t;
+ Y *= t;
+ Z *= t;
+ return *this;
+}
+
+// normalize vector (homogeneous coordinate will be set to one) ---------------
+inline int Vector3::Normalize()
+{
+ if ( IsNullVector() )
+ return FALSE;
+
+ double oonorm = 1 / VecLength();
+ X = X * oonorm;
+ Y = Y * oonorm;
+ Z = Z * oonorm;
+ W = 1.0;
+ return TRUE;
+}
+
+// homogenize vector (divide by homogeneous coordinate) -----------------------
+inline int Vector3::Homogenize()
+{
+ if ( fabs( W ) < EPS_DENOM_ZERO )
+ return FALSE;
+
+ double oow = 1 / W;
+ X = X * oow;
+ Y = Y * oow;
+ Z = Z * oow;
+ W = 1.0;
+ return TRUE;
+}
+
+// check if vector has length zero (employs an epsilon area) ------------------
+inline int Vector3::IsNullVector() const
+{
+ // the epsilon area is employed componentwise, not for the length itself!
+ return ( ( fabs( X ) < EPS_COMP_ZERO ) && ( fabs( Y ) < EPS_COMP_ZERO ) && ( fabs( Z ) < EPS_COMP_ZERO ) );
+}
+
+// calculate length of three dimensional vector -------------------------------
+inline hprec_t Vector3::VecLength() const
+{
+ return sqrt( X * X + Y * Y + Z * Z );
+}
+
+// calculate floating point scalar-product ------------------------------------
+inline hprec_t Vector3::DotProduct( const Vector3& vect ) const
+{
+ return ( vect.X * X ) + ( vect.Y * Y ) + ( vect.Z * Z );
+}
+
+// calculate floating point cross-product -------------------------------------
+inline void Vector3::CrossProduct( const Vector3& vect1, const Vector3& vect2 )
+{
+ X = ( vect1.Y * vect2.Z ) - ( vect1.Z * vect2.Y );
+ Y = ( vect1.Z * vect2.X ) - ( vect1.X * vect2.Z );
+ Z = ( vect1.X * vect2.Y ) - ( vect1.Y * vect2.X );
+ W = 1.0;
+}
+
+// calc vector directed from second vertex to first vertex --------------------
+inline void Vector3::CreateDirVec( const Vertex3& vertex1, const Vertex3& vertex2 )
+{
+ X = vertex2.X - vertex1.X;
+ Y = vertex2.Y - vertex1.Y;
+ Z = vertex2.Z - vertex1.Z;
+ W = 1.0;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VECTOR3_H_
+
diff --git a/tool_src/BspLib/Vertex.cpp b/tool_src/BspLib/Vertex.cpp
new file mode 100644
index 0000000..f46b038
--- /dev/null
+++ b/tool_src/BspLib/Vertex.cpp
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: Vertex.cpp
+//
+// Copyright (c) 1996-1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Vertex.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// set specified coordinate to specified value --------------------------------
+void Vertex3::ChangeAxis( const char xchar, const hprec_t src )
+{
+ switch ( xchar ) {
+ case 'x':
+ X = src;
+ break;
+ case 'y':
+ Y = src;
+ break;
+ case 'z':
+ Z = src;
+ break;
+ default:
+ fflush( stdout );
+ fprintf( stderr, "\n\n**ERROR** [illegal xchange parameters]\n" );
+ exit( EXIT_FAILURE );
+ }
+}
+
+// change all axes according to xchange-command -------------------------------
+void Vertex3::ChangeAxes( const char *xchangecmd, const Vertex3& ads )
+{
+ Vertex3 temp = *this;
+ ChangeAxis( xchangecmd[ 0 ], temp.X * ads.X );
+ ChangeAxis( xchangecmd[ 1 ], temp.Y * ads.Y );
+ ChangeAxis( xchangecmd[ 2 ], temp.Z * ads.Z );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/Vertex.h b/tool_src/BspLib/Vertex.h
new file mode 100644
index 0000000..7a4db5f
--- /dev/null
+++ b/tool_src/BspLib/Vertex.h
@@ -0,0 +1,206 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Vertex.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VERTEX_H_
+#define _VERTEX_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// single 3-D vertex ----------------------------------------------------------
+//
+class Vertex3 {
+
+ friend class Vector3;
+ friend class LineSeg3;
+
+ friend int operator ==( const Vertex3 v1, const Vertex3 v2 );
+ friend int operator !=( const Vertex3 v1, const Vertex3 v2 );
+
+ friend class Vector3 operator -( const Vertex3 v1, const Vertex3 v2 );
+
+ friend Vertex3 operator +( const Vertex3 v1, const class ector3 v2 );
+ friend Vertex3 operator +( const class Vector3 v1, const Vertex3 v2 );
+ friend Vertex3 operator -( const Vertex3 v1, const class Vector3 v2 );
+
+public:
+ Vertex3( hprec_t x = 0, hprec_t y = 0, hprec_t z = 0, hprec_t w = 1.0 );
+ ~Vertex3() { }
+
+ Vertex3& operator +=( const Vector3 v );
+ Vertex3& operator -=( const Vector3 v );
+
+ int IsInVicinity( const Vertex3& vertex ) const;
+ void ChangeAxes( const char *xchangecmd, const Vertex3& ads );
+
+ hprec_t getX() const { return X; }
+ hprec_t getY() const { return Y; }
+ hprec_t getZ() const { return Z; }
+ hprec_t getW() const { return W; }
+
+ void setX( hprec_t x ) { X = x; }
+ void setY( hprec_t y ) { Y = y; }
+ void setZ( hprec_t z ) { Z = z; }
+ void setW( hprec_t w ) { W = w; }
+ hprec_t X;
+ hprec_t Y;
+ hprec_t Z;
+ hprec_t W;
+
+private:
+ void ChangeAxis( const char xchar, const hprec_t src );
+
+protected:
+};
+
+
+// single 3-D vector ----------------------------------------------------------
+//
+class Vector3 : public Vertex3 {
+
+ friend class LineSeg3;
+
+ friend Vector3 operator -( const Vertex3 v1, const Vertex3 v2 );
+
+ friend Vertex3 operator +( const Vertex3 v1, const Vector3 v2 );
+ friend Vertex3 operator +( const Vector3 v1, const Vertex3 v2 );
+ friend Vertex3 operator -( const Vertex3 v1, const Vector3 v2 );
+
+ friend Vector3 operator +( const Vector3 v1, const Vector3 v2 );
+ friend Vector3 operator -( const Vector3 v1, const Vector3 v2 );
+
+ friend Vector3 operator *( const Vector3 v1, double t );
+ friend Vector3 operator *( double t, const Vector3 v1 );
+
+public:
+ Vector3( hprec_t x = 0, hprec_t y = 0, hprec_t z = 0, hprec_t w = 1.0 )
+ : Vertex3( x, y, z, w ) { }
+ // initialize as direction vector
+ Vector3( const Vertex3& v1, const Vertex3& v2 )
+ : Vertex3( v2.X - v1.X, v2.Y - v1.Y, v2.Z - v1.Z ) { }
+ // initialize as cross product
+ Vector3( const Vector3& v1, const Vector3& v2 );
+ // conversion from Vertex3
+ Vector3( const Vertex3& vtx ) { *(Vertex3*)this = vtx; }
+ ~Vector3() { }
+
+ Vector3& operator +=( const Vector3 v );
+ Vector3& operator -=( const Vector3 v );
+
+ Vector3& operator *=( double t );
+
+ int Normalize();
+ int Homogenize();
+ int IsNullVector() const;
+ hprec_t VecLength() const;
+ hprec_t DotProduct( const Vector3& vect ) const;
+ void CrossProduct( const Vector3& vect1, const Vector3& vect2 );
+ void CreateDirVec( const Vertex3& vertex1, const Vertex3& vertex2 );
+};
+
+
+// single 2-D vertex ----------------------------------------------------------
+//
+class Vertex2 {
+
+ friend class Vector2;
+ friend class LineSeg2;
+
+ friend int operator ==( const Vertex2 v1, const Vertex2 v2 );
+ friend int operator !=( const Vertex2 v1, const Vertex2 v2 );
+
+ friend class Vector2 operator -( const Vertex2 v1, const Vertex2 v2 );
+
+ friend Vertex2 operator +( const Vertex2 v1, const class Vector2 v2 );
+ friend Vertex2 operator +( const class Vector2 v1, const Vertex2 v2 );
+ friend Vertex2 operator -( const Vertex2 v1, const class Vector2 v2 );
+
+public:
+ Vertex2( hprec_t x = 0, hprec_t y = 0, hprec_t w = 1.0 ) { X = x; Y = y; W = w; }
+ // conversion Vector2 -> Vertex2
+ Vertex2( const Vector2& vect );
+ ~Vertex2() { }
+
+ Vertex2& operator +=( const Vector2 v );
+ Vertex2& operator -=( const Vector2 v );
+
+ int IsInVicinity( const Vertex2& vertex ) const;
+ void InitFromVertex3( const Vertex3& vertex );
+
+ hprec_t getX() const { return X; }
+ hprec_t getY() const { return Y; }
+ hprec_t getW() const { return W; }
+
+ void setX( hprec_t x ) { X = x; }
+ void setY( hprec_t y ) { Y = y; }
+ void setW( hprec_t w ) { W = w; }
+
+protected:
+ hprec_t X;
+ hprec_t Y;
+ hprec_t W;
+};
+
+
+// single 2-D vector ----------------------------------------------------------
+//
+class Vector2 : public Vertex2 {
+
+ friend class LineSeg2;
+
+ friend Vector2 operator -( const Vertex2 v1, const Vertex2 v2 );
+
+ friend Vertex2 operator +( const Vertex2 v1, const Vector2 v2 );
+ friend Vertex2 operator +( const Vector2 v1, const Vertex2 v2 );
+ friend Vertex2 operator -( const Vertex2 v1, const Vector2 v2 );
+
+ friend Vector2 operator +( const Vector2 v1, const Vector2 v2 );
+ friend Vector2 operator -( const Vector2 v1, const Vector2 v2 );
+
+ friend Vector2 operator *( const Vector2 v1, double t );
+ friend Vector2 operator *( double t, const Vector2 v1 );
+
+public:
+ Vector2( hprec_t x = 0, hprec_t y = 0, hprec_t w = 1.0 )
+ : Vertex2( x, y, w ) { }
+ // initialize as direction vector
+ Vector2( const Vertex2& v1, const Vertex2& v2 )
+ : Vertex2( v2.X - v1.X, v2.Y - v1.Y ) { }
+ // conversion from Vertex2
+ Vector2( const Vertex2& vtx ) { *(Vertex2*)this = vtx; }
+ ~Vector2() { }
+
+ Vector2& operator +=( const Vector2 v );
+ Vector2& operator -=( const Vector2 v );
+
+ Vector2& operator *=( double t );
+
+ int Normalize();
+ int Homogenize();
+ int IsNullVector() const;
+ hprec_t VecLength() const;
+ hprec_t DotProduct( const Vector2& vect ) const;
+ void CreateDirVec( const Vertex2& vertex, const Vertex2& dirvec );
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+// include vector and lineseg capability, and chunks of vertices
+#include "Vector.h"
+#include "LineSeg2.h"
+#include "LineSeg3.h"
+#include "VertexChunk.h"
+
+
+#endif // _VERTEX_H_
+
diff --git a/tool_src/BspLib/Vertex2.h b/tool_src/BspLib/Vertex2.h
new file mode 100644
index 0000000..5ebf100
--- /dev/null
+++ b/tool_src/BspLib/Vertex2.h
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Vertex2.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VERTEX2_H_
+#define _VERTEX2_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// conversion from Vector2 to Vertex2 -----------------------------------------
+inline Vertex2::Vertex2( const Vector2& vect )
+{
+ X = vect.X;
+ Y = vect.Y;
+ W = vect.W;
+}
+
+// operator '==' does memberwise comparison for (X,Y,W) -----------------------
+inline int operator ==( const Vertex2 v1, const Vertex2 v2 )
+{
+ return ( ( v1.X == v2.X ) && ( v1.Y == v2.Y ) && ( v1.W == v2.W ) );
+}
+
+// operator '!=' does memberwise comparison for (X,Y,W) -----------------------
+inline int operator !=( const Vertex2 v1, const Vertex2 v2 )
+{
+ return ( ( v1.X != v2.X ) || ( v1.Y != v2.Y ) || ( v1.W != v2.W ) );
+}
+
+// operator '+=' does memberwise addition for (X,Y) ---------------------------
+inline Vertex2& Vertex2::operator +=( const Vector2 v )
+{
+ X += v.X;
+ Y += v.Y;
+
+ return *this;
+}
+
+// operator '-=' does memberwise subtraction for (X,Y) ------------------------
+inline Vertex2& Vertex2::operator -=( const Vector2 v )
+{
+ X -= v.X;
+ Y -= v.Y;
+
+ return *this;
+}
+
+// check if specified vertex is in vicinity of local vertex -------------------
+inline int Vertex2::IsInVicinity( const Vertex2& vertex ) const
+{
+ return ( ( fabs( X - vertex.X ) < EPS_VERTEX_MERGE ) &&
+ ( fabs( Y - vertex.Y ) < EPS_VERTEX_MERGE ) );
+}
+
+// copy three coordinates into two plus w -------------------------------------
+inline void Vertex2::InitFromVertex3( const Vertex3& vertex )
+{
+ X = vertex.getX();
+ Y = vertex.getY();
+ W = vertex.getZ();
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VERTEX2_H_
+
diff --git a/tool_src/BspLib/Vertex3.h b/tool_src/BspLib/Vertex3.h
new file mode 100644
index 0000000..113b9c2
--- /dev/null
+++ b/tool_src/BspLib/Vertex3.h
@@ -0,0 +1,72 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: Vertex3.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VERTEX3_H_
+#define _VERTEX3_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// construct Vertex3 by initializing member coordinates -----------------------
+inline Vertex3::Vertex3( hprec_t x, hprec_t y, hprec_t z, hprec_t w )
+{
+ X = x;
+ Y = y;
+ Z = z;
+ W = w;
+}
+
+// operator '==' does memberwise comparison for (X,Y,Z,W) ---------------------
+inline int operator ==( const Vertex3 v1, const Vertex3 v2 )
+{
+ return ( ( v1.X == v2.X ) && ( v1.Y == v2.Y ) && ( v1.Z == v2.Z ) && ( v1.W == v2.W ) );
+}
+
+// operator '!=' does memberwise comparison for (X,Y,Z,W) ---------------------
+inline int operator !=( const Vertex3 v1, const Vertex3 v2 )
+{
+ return ( ( v1.X != v2.X ) || ( v1.Y != v2.Y ) || ( v1.Z != v2.Z ) || ( v1.W != v2.W ) );
+}
+
+// operator '+=' does memberwise addition for (X,Y,Z) -------------------------
+inline Vertex3& Vertex3::operator +=( const Vector3 v )
+{
+ X += v.X;
+ Y += v.Y;
+ Z += v.Z;
+
+ return *this;
+}
+
+// operator '-=' does memberwise subtraction for (X,Y,Z) ----------------------
+inline Vertex3& Vertex3::operator -=( const Vector3 v )
+{
+ X -= v.X;
+ Y -= v.Y;
+ Z -= v.Z;
+
+ return *this;
+}
+
+// check if specified vertex is in vicinity of local vertex -------------------
+inline int Vertex3::IsInVicinity( const Vertex3& vertex ) const
+{
+ return ( ( fabs( X - vertex.X ) < EPS_VERTEX_MERGE ) &&
+ ( fabs( Y - vertex.Y ) < EPS_VERTEX_MERGE ) &&
+ ( fabs( Z - vertex.Z ) < EPS_VERTEX_MERGE ) );
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VERTEX3_H_
+
diff --git a/tool_src/BspLib/VertexChunk.cpp b/tool_src/BspLib/VertexChunk.cpp
new file mode 100644
index 0000000..8bce25a
--- /dev/null
+++ b/tool_src/BspLib/VertexChunk.cpp
@@ -0,0 +1,237 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: VertexChunk.cpp
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib headers
+#include "Vertex.h"
+
+
+// if this flag is set storage is increased by using lists.
+// this can be very inefficient and should only be used for
+// testing purposes!
+// if not set, storage is expanded in realloc() style.
+//#define EXPAND_STORAGE_WITH_LISTS
+
+// if this flag is set storage is always increased two-fold
+#define EXPAND_EXPONENTIALLY
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// return number of vertices in entire vertex chunk list ----------------------
+//
+int VertexChunkRep::getNumElements() const
+{
+ int num = 0;
+ for ( const VertexChunkRep *vlist = this; vlist; vlist = vlist->next )
+ num += vlist->numvertices;
+ return num;
+}
+
+
+// fetch index to specified vertex if vertex already exists -------------------
+//
+int VertexChunkRep::FindVertex( const Vertex3& vertex )
+{
+ int numskipped = 0;
+
+ VertexChunkRep *vlist = this;
+ while ( ( vlist != NULL ) && ( vlist->numvertices > 0 ) ) {
+ for ( int i = 0; i < vlist->numvertices; i++ )
+ if ( vertices[ i ] == vertex )
+ return i + numskipped;
+ numskipped += vlist->numvertices;
+ vlist = vlist->next;
+ }
+
+ // vertex not found
+ return -1;
+}
+
+
+// fetch vertex-index if close enough vertex already exists -------------------
+//
+int VertexChunkRep::FindCloseVertex( const Vertex3& vertex, int skip )
+{
+ int numskipped = 0;
+
+ VertexChunkRep *vlist = this;
+ while ( ( vlist != NULL ) && ( vlist->numvertices > 0 ) ) {
+ for ( int i = 0; i < vlist->numvertices; i++ )
+ if ( ( i + numskipped > skip ) && vertices[ i ].IsInVicinity( vertex ) )
+ return i + numskipped;
+ numskipped += vlist->numvertices;
+ vlist = vlist->next;
+ }
+
+ // vertex not found
+ return -1;
+}
+
+
+// fetch vertex corresponding to specific index -------------------------------
+//
+Vertex3& VertexChunkRep::FetchVertex( int index )
+{
+
+#ifdef EXPAND_STORAGE_WITH_LISTS
+
+ VertexChunkRep *vlist = this;
+ while ( ( vlist != NULL ) && ( index >= vlist->numvertices ) ) {
+ index -= vlist->numvertices;
+ vlist = vlist->next;
+ }
+
+ if ( vlist == NULL ) {
+ // invalid index (too large)
+ ErrorMessage( "\n***ERROR*** Invalid index in VertexChunk.\n" );
+ HandleCriticalError();
+ }
+
+ // return vertex
+ return vlist->vertices[ index ];
+
+#else
+
+ if ( index >= numvertices ) {
+ // invalid index (too large)
+ ErrorMessage( "\n***ERROR*** Invalid index in VertexChunk.\n" );
+ HandleCriticalError();
+ }
+
+ // return vertex
+ return vertices[ index ];
+
+#endif
+
+}
+
+
+// check if multiple vertices exist for the same actual point -----------------
+//
+int VertexChunkRep::CheckVertices( int verbose )
+{
+ StrScratch message;
+
+ if ( verbose ) {
+ InfoMessage( "\nChecking vertices...\n" );
+ }
+
+ nummultvertices = 0;
+ int multi = 0;
+ for ( int i = 0; i < getNumElements(); i++ ) {
+ int vertindx = FindCloseVertex( FetchVertex( i ), i );
+ if ( vertindx != -1 ) {
+ if ( verbose ) {
+ if ( multi == 0 ) {
+ InfoMessage( "*** multiple vertices found ***\n" );
+ multi++;
+ }
+ sprintf( message, "Vertex %d is same as %d\n", i + 1, vertindx + 1 );
+ InfoMessage( message );
+ }
+ nummultvertices++;
+ }
+ }
+
+ return nummultvertices;
+}
+
+
+// insert vertex into list of vertex chunks, return index; check doublets -----
+//
+int VertexChunkRep::AddVertex( Vertex3 vertex )
+{
+
+#ifdef EXPAND_STORAGE_WITH_LISTS
+
+ // if vertex contained in head-chunk return index
+ if ( eliminatedoublets )
+ for ( int i = 0; i < numvertices; i++ )
+ if ( VerticesEqual( vertices[ i ], vertex ) )
+ return i;
+
+ // if space in head-chunk insert vertex directly
+ if ( numvertices < maxnumvertices ) {
+
+ vertices[ numvertices ] = vertex;
+ return numvertices++;
+
+ } else {
+
+ int numskipped = numvertices;
+ VertexChunkRep *vlist = this;
+
+ // scan until non-full chunk found
+ while ( ( vlist->next != NULL ) && ( vlist->next->numvertices == vlist->next->maxnumvertices ) ) {
+
+ if ( eliminatedoublets )
+ for ( int i = 0; i < vlist->next->numvertices; i++ )
+ if ( VerticesEqual( vlist->next->vertices[ i ], vertex ) )
+ return i + numskipped;
+ vlist = vlist->next;
+ numskipped += vlist->numvertices;
+ }
+
+ if ( vlist->next == NULL ) {
+ // insert new chunk if all existing are full
+#ifdef EXPAND_EXPONENTIALLY
+ vlist->next = new VertexChunkRep( vlist->maxnumvertices * 2 );
+#else
+ vlist->next = new VertexChunkRep;
+#endif
+ } else {
+ if ( eliminatedoublets )
+ for ( int i = 0; i < vlist->next->numvertices; i++ )
+ if ( VerticesEqual( vlist->next->vertices[ i ], vertex ) )
+ return i + numskipped;
+ }
+
+ // insert new vertex
+ vlist->next->vertices[ vlist->next->numvertices ] = vertex;
+ return vlist->next->numvertices++ + numskipped;
+ }
+
+#else
+
+ // if vertex already contained in chunk return index
+ if ( eliminatedoublets )
+ for ( int i = 0; i < numvertices; i++ )
+ if ( VerticesEqual( vertices[ i ], vertex ) )
+ return i;
+
+ // expand storage if necessary
+ if ( numvertices == maxnumvertices ) {
+
+#ifdef EXPAND_EXPONENTIALLY
+ maxnumvertices *= 2;
+#else
+ maxnumvertices += CHUNK_SIZE;
+#endif
+ Vertex3 *temp = new Vertex3[ maxnumvertices ];
+ memcpy( temp, vertices, numvertices * sizeof( Vertex3 ) );
+ delete[] vertices;
+ vertices = temp;
+ }
+
+ vertices[ numvertices ] = vertex;
+ return numvertices++;
+
+#endif
+
+}
+
+
+// VertexChunkRep specific static variables -----------------------------------
+//
+const int VertexChunkRep::CHUNK_SIZE = 256;
+int VertexChunkRep::eliminatedoublets = 0;
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/VertexChunk.h b/tool_src/BspLib/VertexChunk.h
new file mode 100644
index 0000000..dd5274a
--- /dev/null
+++ b/tool_src/BspLib/VertexChunk.h
@@ -0,0 +1,129 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: VertexChunk.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VERTEXCHUNK_H_
+#define _VERTEXCHUNK_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "SystemIO.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// chunk of 3-D vertices (actual representation) ------------------------------
+//
+class VertexChunkRep : public virtual SystemIO {
+
+ friend class VertexChunk;
+
+private:
+ VertexChunkRep( int chunksize = 0 );
+ ~VertexChunkRep();
+
+ Vertex3& FetchVertex( int index );
+ int AddVertex( Vertex3 vertex );
+ int FindVertex( const Vertex3& vertex );
+ int FindCloseVertex( const Vertex3& vertex, int skip = -1 );
+ int CheckVertices( int verbose );
+
+ int getNumElements() const;
+
+private:
+ void ChangeAxis( char xchar, hprec_t src );
+ int VerticesEqual( Vertex3 v1, Vertex3 v2 );
+
+private:
+ int ref_count;
+
+ int numvertices;
+ int maxnumvertices;
+ Vertex3* vertices;
+ VertexChunkRep* next;
+
+ int nummultvertices;
+ static int eliminatedoublets;
+ static const int CHUNK_SIZE;
+};
+
+// create new vertex chunk ----------------------------------------------------
+inline VertexChunkRep::VertexChunkRep( int chunksize ) : ref_count( 0 )
+{
+ int challocsize = chunksize > 0 ? chunksize : CHUNK_SIZE;
+ vertices = new Vertex3[ challocsize ];
+ maxnumvertices = challocsize;
+ numvertices = 0;
+ next = NULL;
+}
+
+// destroy list of vertex chunks recursively ----------------------------------
+inline VertexChunkRep::~VertexChunkRep()
+{
+ delete next;
+ delete[] vertices;
+}
+
+// check if two vertices are equal --------------------------------------------
+inline int VertexChunkRep::VerticesEqual( Vertex3 v1, Vertex3 v2 )
+{
+// return v1.IsInVicinity( v2 );
+ return ( v1 == v2 );
+}
+
+
+// chunk of 3-D vertices (handle class) ---------------------------------------
+//
+class VertexChunk {
+
+public:
+ VertexChunk( int chunksize = 0 ) { rep = new VertexChunkRep( chunksize ); rep->ref_count = 1; }
+ ~VertexChunk() { if ( --rep->ref_count == 0 ) delete rep; }
+
+ VertexChunk( const VertexChunk& copyobj );
+ VertexChunk& operator =( const VertexChunk& copyobj );
+
+ Vertex3& operator []( int index ) { return rep->FetchVertex( index ); }
+ Vertex3& FetchVertex( int index ) { return rep->FetchVertex( index ); }
+
+ int AddVertex( const Vertex3 vertex ) { return rep->AddVertex( vertex ); }
+ int FindVertex( const Vertex3& vertex ) { return rep->FindVertex( vertex ); }
+ int FindCloseVertex( Vertex3 vertex, int skip = -1 ) { return rep->FindCloseVertex( vertex, skip ); }
+ int CheckVertices( int verbose ) { return rep->CheckVertices( verbose ); }
+
+ int getNumElements() const { return rep->getNumElements(); }
+
+private:
+ VertexChunkRep* rep;
+};
+
+// copy constructor for VertexChunk -------------------------------------------
+inline VertexChunk::VertexChunk( const VertexChunk& copyobj )
+{
+ rep = copyobj.rep;
+ rep->ref_count++;
+}
+
+// assignment operator for VertexChunk ----------------------------------------
+inline VertexChunk& VertexChunk::operator =( const VertexChunk& copyobj )
+{
+ if ( &copyobj != this ) {
+ if ( --rep->ref_count == 0 ) {
+ delete rep;
+ }
+ rep = copyobj.rep;
+ rep->ref_count++;
+ }
+ return *this;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VERTEXCHUNK_H_
+
diff --git a/tool_src/BspLib/VrmlFile.cpp b/tool_src/BspLib/VrmlFile.cpp
new file mode 100644
index 0000000..64f2df1
--- /dev/null
+++ b/tool_src/BspLib/VrmlFile.cpp
@@ -0,0 +1,133 @@
+//-----------------------------------------------------------------------------
+// BSPLIB MODULE: VrmlFile.cpp
+//
+// Copyright (c) 1997-1998 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+// bsplib header files
+#include "VrmlFile.h"
+#include "BspObject.h"
+#include "BspTool.h"
+
+// qvlib header files
+#include <QvDB.h>
+#include <QvInput.h>
+#include <QvNode.h>
+#include <QvState.h>
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+// file is read and parsed immediately after construction ---------------------
+//
+VrmlFile::VrmlFile( BspObjectList objectlist, const char *filename ) :
+ InputData3D( objectlist, filename, DONT_CREATE_OBJECT ),
+ m_bboxlist( NULL )
+{
+ ParseObjectData();
+}
+
+
+// write outputfile before destruction ----------------------------------------
+//
+VrmlFile::~VrmlFile()
+{
+ if ( m_inputok && !m_filename.IsNULL() )
+ WriteOutputFile();
+ delete m_bboxlist;
+}
+
+
+// apply all transformations to scene -----------------------------------------
+//
+void VrmlFile::ApplySceneTransformations()
+{
+ BspObject *sceneobj = m_objectlist.getListHead();
+ for ( ; sceneobj; sceneobj = sceneobj->getNext() )
+ sceneobj->ApplyTransformation();
+}
+
+
+// enforce maximum extents for entire scene -----------------------------------
+//
+void VrmlFile::EnforceSceneExtents( BoundingBox& unionbox )
+{
+ double fmext = getMaxExtents();
+
+ Vertex3 minvertex = unionbox.getMinVertex();
+ Vertex3 maxvertex = unionbox.getMaxVertex();
+
+ double extent_x = maxvertex.getX() - minvertex.getX();
+ double extent_y = maxvertex.getY() - minvertex.getY();
+ double extent_z = maxvertex.getZ() - minvertex.getZ();
+
+ double mext = extent_x;
+ if ( extent_y > mext ) mext = extent_y;
+ if ( extent_z > mext ) mext = extent_z;
+ double cfac = fmext / mext;
+
+ BspObject *sceneobj = m_objectlist.getListHead();
+ for ( ; sceneobj; sceneobj = sceneobj->getNext() )
+ sceneobj->ApplyScale( cfac );
+}
+
+
+// parse vrml 1.0 file and build data structures for all contained objects ----
+//
+int VrmlFile::ParseObjectData()
+{
+ // open input data file
+ FileAccess input( m_filename, "r" );
+ InfoMessage( "Processing input data file (format='VRML V1.0') ..." );
+
+ // init qvlib database
+ QvDB::init();
+
+ // tie input file to QvInput object
+ QvInput inputdata;
+ inputdata.setFilePointer( input );
+
+ // read and parse vrml input data
+ QvNode *vrmlroot = NULL;
+ if ( QvDB::read( &inputdata, vrmlroot ) && ( vrmlroot != NULL ) ) {
+ InfoMessage( "\nObject data ok.\n" );
+ m_inputok = TRUE;
+ } else {
+ sprintf( line, "%sVRML tree data invalid.\n", parser_err_str );
+ ErrorMessage( line );
+ HandleCriticalError( CRITERR_ALLOW_RET );
+ delete vrmlroot;
+ return ( m_inputok = FALSE );
+ }
+
+ // create object for traversal state
+ QvState state( this );
+
+ // traverse entire vrml tree and construct scene representation for bsplib
+ vrmlroot->traverse( &state );
+
+ // if scene scale desired calculate union bounding box and scale entire scene
+ if ( getEnforceExtentsFlag() && ( m_bboxlist != NULL ) ) {
+ BoundingBox unionbox;
+ m_bboxlist->BoundingBoxListUnion( unionbox );
+ EnforceSceneExtents( unionbox );
+ }
+
+ delete vrmlroot;
+ return m_inputok;
+}
+
+
+// write output file(s) for objects constructed out of vrml file --------------
+//
+int VrmlFile::WriteOutputFile()
+{
+ return FALSE;
+}
+
+
+BSPLIB_NAMESPACE_END
+
+//-----------------------------------------------------------------------------
diff --git a/tool_src/BspLib/VrmlFile.h b/tool_src/BspLib/VrmlFile.h
new file mode 100644
index 0000000..7b0dfd6
--- /dev/null
+++ b/tool_src/BspLib/VrmlFile.h
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------------
+// BSPLIB HEADER: VrmlFile.h
+//
+// Copyright (c) 1997 by Markus Hadwiger
+// All Rights Reserved.
+//-----------------------------------------------------------------------------
+
+#ifndef _VRMLFILE_H_
+#define _VRMLFILE_H_
+
+// bsplib header files
+#include "BspLibDefs.h"
+#include "BoundingBox.h"
+#include "InputData3D.h"
+
+
+BSPLIB_NAMESPACE_BEGIN
+
+
+class BspObjectList;
+
+// file manipulation class for vrml format files ------------------------------
+//
+class VrmlFile : public InputData3D {
+
+ friend class BRep;
+
+public:
+ VrmlFile( BspObjectList objectlist, const char *filename );
+ ~VrmlFile();
+
+ int ParseObjectData();
+ int WriteOutputFile();
+
+private:
+ void ApplySceneTransformations();
+ void EnforceSceneExtents( BoundingBox& unionbox );
+
+private:
+ BoundingBox* m_bboxlist;
+};
+
+
+BSPLIB_NAMESPACE_END
+
+
+#endif // _VRMLFILE_H_
+