diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
| commit | c068f22329d5cc722622a2183bbb22eef2093df7 (patch) | |
| tree | 12d56c1aede67988a55e241364606bfbb4dba933 /tool_src/BspLib | |
| download | openparsec-main.tar.xz openparsec-main.zip | |
Diffstat (limited to 'tool_src/BspLib')
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 ( ©obj != 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 ( ©obj != 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=""$/ParsecTools/BspLib", 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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 ( ©obj != 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_ + |
