doom3-bfg/neo/idlib/MapFile.cpp

1677 lines
36 KiB
C++
Raw Normal View History

2012-11-26 18:58:24 +00:00
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015 Robert Beckebans
2012-11-26 18:58:24 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
/*
===============
FloatCRC
===============
*/
ID_INLINE unsigned int FloatCRC( float f )
{
return *( unsigned int* )&f;
2012-11-26 18:58:24 +00:00
}
/*
===============
StringCRC
===============
*/
ID_INLINE unsigned int StringCRC( const char* str )
{
2012-11-26 18:58:24 +00:00
unsigned int i, crc;
const unsigned char* ptr;
2012-11-26 18:58:24 +00:00
crc = 0;
ptr = reinterpret_cast<const unsigned char*>( str );
for( i = 0; str[i]; i++ )
{
crc ^= str[i] << ( i & 3 );
2012-11-26 18:58:24 +00:00
}
return crc;
}
/*
=================
ComputeAxisBase
WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
rotation by (0,RotY,RotZ) assigns X to normal
=================
*/
static void ComputeAxisBase( const idVec3& normal, idVec3& texS, idVec3& texT )
{
2012-11-26 18:58:24 +00:00
float RotY, RotZ;
idVec3 n;
2012-11-26 18:58:24 +00:00
// do some cleaning
n[0] = ( idMath::Fabs( normal[0] ) < 1e-6f ) ? 0.0f : normal[0];
n[1] = ( idMath::Fabs( normal[1] ) < 1e-6f ) ? 0.0f : normal[1];
n[2] = ( idMath::Fabs( normal[2] ) < 1e-6f ) ? 0.0f : normal[2];
RotY = -atan2( n[2], idMath::Sqrt( n[1] * n[1] + n[0] * n[0] ) );
2012-11-26 18:58:24 +00:00
RotZ = atan2( n[1], n[0] );
// rotate (0,1,0) and (0,0,1) to compute texS and texT
texS[0] = -sin( RotZ );
texS[1] = cos( RotZ );
2012-11-26 18:58:24 +00:00
texS[2] = 0;
// the texT vector is along -Z ( T texture coorinates axis )
texT[0] = -sin( RotY ) * cos( RotZ );
texT[1] = -sin( RotY ) * sin( RotZ );
texT[2] = -cos( RotY );
2012-11-26 18:58:24 +00:00
}
/*
=================
idMapBrushSide::GetTextureVectors
=================
*/
void idMapBrushSide::GetTextureVectors( idVec4 v[2] ) const
{
2012-11-26 18:58:24 +00:00
int i;
idVec3 texX, texY;
2012-11-26 18:58:24 +00:00
ComputeAxisBase( plane.Normal(), texX, texY );
for( i = 0; i < 2; i++ )
{
2012-11-26 18:58:24 +00:00
v[i][0] = texX[0] * texMat[i][0] + texY[0] * texMat[i][1];
v[i][1] = texX[1] * texMat[i][0] + texY[1] * texMat[i][1];
v[i][2] = texX[2] * texMat[i][0] + texY[2] * texMat[i][1];
v[i][3] = texMat[i][2] + ( origin * v[i].ToVec3() );
}
}
/*
=================
idMapPatch::Parse
=================
*/
idMapPatch* idMapPatch::Parse( idLexer& src, const idVec3& origin, bool patchDef3, float version )
{
2012-11-26 18:58:24 +00:00
float info[7];
idDrawVert* vert;
2012-11-26 18:58:24 +00:00
idToken token;
int i, j;
if( !src.ExpectTokenString( "{" ) )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
2012-11-26 18:58:24 +00:00
// read the material (we had an implicit 'textures/' in the old format...)
if( !src.ReadToken( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: unexpected EOF" );
return NULL;
}
2012-11-26 18:58:24 +00:00
// Parse it
if( patchDef3 )
{
if( !src.Parse1DMatrix( 7, info ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: unable to Parse patchDef3 info" );
return NULL;
}
}
else
{
if( !src.Parse1DMatrix( 5, info ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: unable to parse patchDef2 info" );
return NULL;
}
}
idMapPatch* patch = new( TAG_IDLIB ) idMapPatch( info[0], info[1] );
2012-11-26 18:58:24 +00:00
patch->SetSize( info[0], info[1] );
if( version < 2.0f )
{
2012-11-26 18:58:24 +00:00
patch->SetMaterial( "textures/" + token );
}
else
{
2012-11-26 18:58:24 +00:00
patch->SetMaterial( token );
}
if( patchDef3 )
{
2012-11-26 18:58:24 +00:00
patch->SetHorzSubdivisions( info[2] );
patch->SetVertSubdivisions( info[3] );
patch->SetExplicitlySubdivided( true );
}
if( patch->GetWidth() < 0 || patch->GetHeight() < 0 )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: bad size" );
delete patch;
return NULL;
}
2012-11-26 18:58:24 +00:00
// these were written out in the wrong order, IMHO
if( !src.ExpectTokenString( "(" ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: bad patch vertex data" );
delete patch;
return NULL;
}
for( j = 0; j < patch->GetWidth(); j++ )
{
if( !src.ExpectTokenString( "(" ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: bad vertex row data" );
delete patch;
return NULL;
}
for( i = 0; i < patch->GetHeight(); i++ )
{
2012-11-26 18:58:24 +00:00
float v[5];
if( !src.Parse1DMatrix( 5, v ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: bad vertex column data" );
delete patch;
return NULL;
}
vert = &( ( *patch )[i * patch->GetWidth() + j] );
2012-11-26 18:58:24 +00:00
vert->xyz[0] = v[0] - origin[0];
vert->xyz[1] = v[1] - origin[1];
vert->xyz[2] = v[2] - origin[2];
vert->SetTexCoord( v[3], v[4] );
}
if( !src.ExpectTokenString( ")" ) )
{
2012-11-26 18:58:24 +00:00
delete patch;
src.Error( "idMapPatch::Parse: unable to parse patch control points" );
return NULL;
}
}
if( !src.ExpectTokenString( ")" ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapPatch::Parse: unable to parse patch control points, no closure" );
delete patch;
return NULL;
}
2012-11-26 18:58:24 +00:00
// read any key/value pairs
while( src.ReadToken( &token ) )
{
if( token == "}" )
{
2012-11-26 18:58:24 +00:00
src.ExpectTokenString( "}" );
break;
}
if( token.type == TT_STRING )
{
2012-11-26 18:58:24 +00:00
idStr key = token;
src.ExpectTokenType( TT_STRING, 0, &token );
patch->epairs.Set( key, token );
}
}
2012-11-26 18:58:24 +00:00
return patch;
}
/*
============
idMapPatch::Write
============
*/
bool idMapPatch::Write( idFile* fp, int primitiveNum, const idVec3& origin ) const
{
2012-11-26 18:58:24 +00:00
int i, j;
const idDrawVert* v;
if( GetExplicitlySubdivided() )
{
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( "// primitive %d\n{\n patchDef3\n {\n", primitiveNum );
fp->WriteFloatString( " \"%s\"\n ( %d %d %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight(), GetHorzSubdivisions(), GetVertSubdivisions() );
}
else
{
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( "// primitive %d\n{\n patchDef2\n {\n", primitiveNum );
fp->WriteFloatString( " \"%s\"\n ( %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight() );
2012-11-26 18:58:24 +00:00
}
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( " (\n" );
idVec2 st;
for( i = 0; i < GetWidth(); i++ )
{
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( " ( " );
for( j = 0; j < GetHeight(); j++ )
{
2012-11-26 18:58:24 +00:00
v = &verts[ j * GetWidth() + i ];
st = v->GetTexCoord();
fp->WriteFloatString( " ( %f %f %f %f %f )", v->xyz[0] + origin[0],
v->xyz[1] + origin[1], v->xyz[2] + origin[2], st[0], st[1] );
2012-11-26 18:58:24 +00:00
}
fp->WriteFloatString( " )\n" );
}
fp->WriteFloatString( " )\n }\n}\n" );
2012-11-26 18:58:24 +00:00
return true;
}
/*
===============
idMapPatch::GetGeometryCRC
===============
*/
unsigned int idMapPatch::GetGeometryCRC() const
{
2012-11-26 18:58:24 +00:00
int i, j;
unsigned int crc;
2012-11-26 18:58:24 +00:00
crc = GetHorzSubdivisions() ^ GetVertSubdivisions();
for( i = 0; i < GetWidth(); i++ )
{
for( j = 0; j < GetHeight(); j++ )
{
2012-11-26 18:58:24 +00:00
crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.x );
crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.y );
crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.z );
}
}
2012-11-26 18:58:24 +00:00
crc ^= StringCRC( GetMaterial() );
2012-11-26 18:58:24 +00:00
return crc;
}
/*
=================
idMapBrush::Parse
=================
*/
idMapBrush* idMapBrush::Parse( idLexer& src, const idVec3& origin, bool newFormat, float version )
{
2012-11-26 18:58:24 +00:00
int i;
idVec3 planepts[3];
idToken token;
idList<idMapBrushSide*> sides;
idMapBrushSide* side;
2012-11-26 18:58:24 +00:00
idDict epairs;
if( !src.ExpectTokenString( "{" ) )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
do
{
if( !src.ReadToken( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unexpected EOF" );
sides.DeleteContents( true );
return NULL;
}
if( token == "}" )
{
2012-11-26 18:58:24 +00:00
break;
}
2012-11-26 18:58:24 +00:00
// here we may have to jump over brush epairs ( only used in editor )
do
{
2012-11-26 18:58:24 +00:00
// if token is a brace
if( token == "(" )
{
2012-11-26 18:58:24 +00:00
break;
}
// the token should be a key string for a key/value pair
if( token.type != TT_STRING )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unexpected %s, expected ( or epair key string", token.c_str() );
sides.DeleteContents( true );
return NULL;
}
2012-11-26 18:58:24 +00:00
idStr key = token;
if( !src.ReadTokenOnLine( &token ) || token.type != TT_STRING )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: expected epair value string not found" );
sides.DeleteContents( true );
return NULL;
}
2012-11-26 18:58:24 +00:00
epairs.Set( key, token );
2012-11-26 18:58:24 +00:00
// try to read the next key
if( !src.ReadToken( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unexpected EOF" );
sides.DeleteContents( true );
return NULL;
}
}
while( 1 );
2012-11-26 18:58:24 +00:00
src.UnreadToken( &token );
side = new( TAG_IDLIB ) idMapBrushSide();
sides.Append( side );
if( newFormat )
{
if( !src.Parse1DMatrix( 4, side->plane.ToFloatPtr() ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unable to read brush side plane definition" );
sides.DeleteContents( true );
return NULL;
}
}
else
{
2012-11-26 18:58:24 +00:00
// read the three point plane definition
if( !src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unable to read brush side plane definition" );
sides.DeleteContents( true );
return NULL;
}
2012-11-26 18:58:24 +00:00
planepts[0] -= origin;
planepts[1] -= origin;
planepts[2] -= origin;
2012-11-26 18:58:24 +00:00
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
}
2012-11-26 18:58:24 +00:00
// read the texture matrix
// this is odd, because the texmat is 2D relative to default planar texture axis
if( !src.Parse2DMatrix( 2, 3, side->texMat[0].ToFloatPtr() ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unable to read brush side texture matrix" );
sides.DeleteContents( true );
return NULL;
}
side->origin = origin;
// read the material
if( !src.ReadTokenOnLine( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::Parse: unable to read brush side material" );
sides.DeleteContents( true );
return NULL;
}
2012-11-26 18:58:24 +00:00
// we had an implicit 'textures/' in the old format...
if( version < 2.0f )
{
2012-11-26 18:58:24 +00:00
side->material = "textures/" + token;
}
else
{
2012-11-26 18:58:24 +00:00
side->material = token;
}
2012-11-26 18:58:24 +00:00
// Q2 allowed override of default flags and values, but we don't any more
if( src.ReadTokenOnLine( &token ) )
{
if( src.ReadTokenOnLine( &token ) )
{
if( src.ReadTokenOnLine( &token ) )
{
2012-11-26 18:58:24 +00:00
}
}
}
}
while( 1 );
if( !src.ExpectTokenString( "}" ) )
{
2012-11-26 18:58:24 +00:00
sides.DeleteContents( true );
return NULL;
}
idMapBrush* brush = new( TAG_IDLIB ) idMapBrush();
for( i = 0; i < sides.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
brush->AddSide( sides[i] );
}
2012-11-26 18:58:24 +00:00
brush->epairs = epairs;
2012-11-26 18:58:24 +00:00
return brush;
}
/*
=================
idMapBrush::ParseQ3
=================
*/
idMapBrush* idMapBrush::ParseQ3( idLexer& src, const idVec3& origin )
{
2012-11-26 18:58:24 +00:00
int i, shift[2], rotate;
float scale[2];
idVec3 planepts[3];
idToken token;
idList<idMapBrushSide*> sides;
idMapBrushSide* side;
2012-11-26 18:58:24 +00:00
idDict epairs;
do
{
if( src.CheckTokenString( "}" ) )
{
2012-11-26 18:58:24 +00:00
break;
}
side = new( TAG_IDLIB ) idMapBrushSide();
2012-11-26 18:58:24 +00:00
sides.Append( side );
2012-11-26 18:58:24 +00:00
// read the three point plane definition
if( !src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
!src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::ParseQ3: unable to read brush side plane definition" );
sides.DeleteContents( true );
return NULL;
}
2012-11-26 18:58:24 +00:00
planepts[0] -= origin;
planepts[1] -= origin;
planepts[2] -= origin;
2012-11-26 18:58:24 +00:00
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
2012-11-26 18:58:24 +00:00
// read the material
if( !src.ReadTokenOnLine( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapBrush::ParseQ3: unable to read brush side material" );
sides.DeleteContents( true );
return NULL;
}
2012-11-26 18:58:24 +00:00
// we have an implicit 'textures/' in the old format
side->material = "textures/" + token;
2012-11-26 18:58:24 +00:00
// read the texture shift, rotate and scale
shift[0] = src.ParseInt();
shift[1] = src.ParseInt();
rotate = src.ParseInt();
scale[0] = src.ParseFloat();
scale[1] = src.ParseFloat();
side->texMat[0] = idVec3( 0.03125f, 0.0f, 0.0f );
side->texMat[1] = idVec3( 0.0f, 0.03125f, 0.0f );
side->origin = origin;
// Q2 allowed override of default flags and values, but we don't any more
if( src.ReadTokenOnLine( &token ) )
{
if( src.ReadTokenOnLine( &token ) )
{
if( src.ReadTokenOnLine( &token ) )
{
2012-11-26 18:58:24 +00:00
}
}
}
}
while( 1 );
idMapBrush* brush = new( TAG_IDLIB ) idMapBrush();
for( i = 0; i < sides.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
brush->AddSide( sides[i] );
}
2012-11-26 18:58:24 +00:00
brush->epairs = epairs;
2012-11-26 18:58:24 +00:00
return brush;
}
/*
============
idMapBrush::Write
============
*/
bool idMapBrush::Write( idFile* fp, int primitiveNum, const idVec3& origin ) const
{
2012-11-26 18:58:24 +00:00
int i;
idMapBrushSide* side;
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( "// primitive %d\n{\n brushDef3\n {\n", primitiveNum );
2012-11-26 18:58:24 +00:00
// write brush epairs
for( i = 0; i < epairs.GetNumKeyVals(); i++ )
{
fp->WriteFloatString( " \"%s\" \"%s\"\n", epairs.GetKeyVal( i )->GetKey().c_str(), epairs.GetKeyVal( i )->GetValue().c_str() );
2012-11-26 18:58:24 +00:00
}
2012-11-26 18:58:24 +00:00
// write brush sides
for( i = 0; i < GetNumSides(); i++ )
{
2012-11-26 18:58:24 +00:00
side = GetSide( i );
fp->WriteFloatString( " ( %f %f %f %f ) ", side->plane[0], side->plane[1], side->plane[2], side->plane[3] );
fp->WriteFloatString( "( ( %f %f %f ) ( %f %f %f ) ) \"%s\" 0 0 0\n",
side->texMat[0][0], side->texMat[0][1], side->texMat[0][2],
side->texMat[1][0], side->texMat[1][1], side->texMat[1][2],
side->material.c_str() );
2012-11-26 18:58:24 +00:00
}
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( " }\n}\n" );
2012-11-26 18:58:24 +00:00
return true;
}
/*
===============
idMapBrush::GetGeometryCRC
===============
*/
unsigned int idMapBrush::GetGeometryCRC() const
{
2012-11-26 18:58:24 +00:00
int i, j;
idMapBrushSide* mapSide;
2012-11-26 18:58:24 +00:00
unsigned int crc;
2012-11-26 18:58:24 +00:00
crc = 0;
for( i = 0; i < GetNumSides(); i++ )
{
mapSide = GetSide( i );
for( j = 0; j < 4; j++ )
{
2012-11-26 18:58:24 +00:00
crc ^= FloatCRC( mapSide->GetPlane()[j] );
}
crc ^= StringCRC( mapSide->GetMaterial() );
}
2012-11-26 18:58:24 +00:00
return crc;
}
/*
================
idMapEntity::Parse
================
*/
idMapEntity* idMapEntity::Parse( idLexer& src, bool worldSpawn, float version )
{
2012-11-26 18:58:24 +00:00
idToken token;
idMapEntity* mapEnt;
idMapPatch* mapPatch;
idMapBrush* mapBrush;
// RB begin
MapPolygonMesh* mapMesh;
// RB end
2012-11-26 18:58:24 +00:00
bool worldent;
idVec3 origin;
double v1, v2, v3;
if( !src.ReadToken( &token ) )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
if( token != "{" )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapEntity::Parse: { not found, found %s", token.c_str() );
return NULL;
}
mapEnt = new( TAG_IDLIB ) idMapEntity();
if( worldSpawn )
{
2012-11-26 18:58:24 +00:00
mapEnt->primitives.Resize( 1024, 256 );
}
2012-11-26 18:58:24 +00:00
origin.Zero();
worldent = false;
do
{
if( !src.ReadToken( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapEntity::Parse: EOF without closing brace" );
return NULL;
}
if( token == "}" )
{
2012-11-26 18:58:24 +00:00
break;
}
if( token == "{" )
{
2012-11-26 18:58:24 +00:00
// parse a brush or patch
if( !src.ReadToken( &token ) )
{
2012-11-26 18:58:24 +00:00
src.Error( "idMapEntity::Parse: unexpected EOF" );
return NULL;
}
if( worldent )
{
2012-11-26 18:58:24 +00:00
origin.Zero();
}
2012-11-26 18:58:24 +00:00
// if is it a brush: brush, brushDef, brushDef2, brushDef3
if( token.Icmpn( "brush", 5 ) == 0 )
{
2012-11-26 18:58:24 +00:00
mapBrush = idMapBrush::Parse( src, origin, ( !token.Icmp( "brushDef2" ) || !token.Icmp( "brushDef3" ) ), version );
if( !mapBrush )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
mapEnt->AddPrimitive( mapBrush );
}
// if is it a patch: patchDef2, patchDef3
else if( token.Icmpn( "patch", 5 ) == 0 )
{
2012-11-26 18:58:24 +00:00
mapPatch = idMapPatch::Parse( src, origin, !token.Icmp( "patchDef3" ), version );
if( !mapPatch )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
mapEnt->AddPrimitive( mapPatch );
}
// RB: new mesh primitive with ngons
else if( token.Icmpn( "mesh", 4 ) == 0 )
{
mapMesh = MapPolygonMesh::Parse( src, origin, version );
if( !mapMesh )
{
return NULL;
}
mapEnt->AddPrimitive( mapMesh );
}
// RB end
2012-11-26 18:58:24 +00:00
// assume it's a brush in Q3 or older style
else
{
2012-11-26 18:58:24 +00:00
src.UnreadToken( &token );
mapBrush = idMapBrush::ParseQ3( src, origin );
if( !mapBrush )
{
2012-11-26 18:58:24 +00:00
return NULL;
}
mapEnt->AddPrimitive( mapBrush );
}
}
else
{
2012-11-26 18:58:24 +00:00
idStr key, value;
2012-11-26 18:58:24 +00:00
// parse a key / value pair
key = token;
src.ReadTokenOnLine( &token );
value = token;
2012-11-26 18:58:24 +00:00
// strip trailing spaces that sometimes get accidentally
// added in the editor
value.StripTrailingWhitespace();
key.StripTrailingWhitespace();
2012-11-26 18:58:24 +00:00
mapEnt->epairs.Set( key, value );
if( !idStr::Icmp( key, "origin" ) )
{
2012-11-26 18:58:24 +00:00
// scanf into doubles, then assign, so it is idVec size independent
v1 = v2 = v3 = 0;
sscanf( value, "%lf %lf %lf", &v1, &v2, &v3 );
origin.x = v1;
origin.y = v2;
origin.z = v3;
}
else if( !idStr::Icmp( key, "classname" ) && !idStr::Icmp( value, "worldspawn" ) )
{
2012-11-26 18:58:24 +00:00
worldent = true;
}
}
}
while( 1 );
2012-11-26 18:58:24 +00:00
return mapEnt;
}
/*
============
idMapEntity::Write
============
*/
bool idMapEntity::Write( idFile* fp, int entityNum ) const
{
2012-11-26 18:58:24 +00:00
int i;
idMapPrimitive* mapPrim;
2012-11-26 18:58:24 +00:00
idVec3 origin;
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( "// entity %d\n{\n", entityNum );
2012-11-26 18:58:24 +00:00
// write entity epairs
for( i = 0; i < epairs.GetNumKeyVals(); i++ )
{
fp->WriteFloatString( "\"%s\" \"%s\"\n", epairs.GetKeyVal( i )->GetKey().c_str(), epairs.GetKeyVal( i )->GetValue().c_str() );
2012-11-26 18:58:24 +00:00
}
2012-11-26 18:58:24 +00:00
epairs.GetVector( "origin", "0 0 0", origin );
2012-11-26 18:58:24 +00:00
// write pritimives
for( i = 0; i < GetNumPrimitives(); i++ )
{
2012-11-26 18:58:24 +00:00
mapPrim = GetPrimitive( i );
switch( mapPrim->GetType() )
{
2012-11-26 18:58:24 +00:00
case idMapPrimitive::TYPE_BRUSH:
static_cast<idMapBrush*>( mapPrim )->Write( fp, i, origin );
2012-11-26 18:58:24 +00:00
break;
case idMapPrimitive::TYPE_PATCH:
static_cast<idMapPatch*>( mapPrim )->Write( fp, i, origin );
2012-11-26 18:58:24 +00:00
break;
// RB begin
case idMapPrimitive::TYPE_MESH:
static_cast<MapPolygonMesh*>( mapPrim )->Write( fp, i, origin );
break;
// RB end
2012-11-26 18:58:24 +00:00
}
}
2012-11-26 18:58:24 +00:00
fp->WriteFloatString( "}\n" );
2012-11-26 18:58:24 +00:00
return true;
}
/*
===============
idMapEntity::RemovePrimitiveData
===============
*/
void idMapEntity::RemovePrimitiveData()
{
primitives.DeleteContents( true );
2012-11-26 18:58:24 +00:00
}
/*
===============
idMapEntity::GetGeometryCRC
===============
*/
unsigned int idMapEntity::GetGeometryCRC() const
{
2012-11-26 18:58:24 +00:00
int i;
unsigned int crc;
idMapPrimitive* mapPrim;
2012-11-26 18:58:24 +00:00
crc = 0;
for( i = 0; i < GetNumPrimitives(); i++ )
{
2012-11-26 18:58:24 +00:00
mapPrim = GetPrimitive( i );
switch( mapPrim->GetType() )
{
2012-11-26 18:58:24 +00:00
case idMapPrimitive::TYPE_BRUSH:
crc ^= static_cast<idMapBrush*>( mapPrim )->GetGeometryCRC();
2012-11-26 18:58:24 +00:00
break;
case idMapPrimitive::TYPE_PATCH:
crc ^= static_cast<idMapPatch*>( mapPrim )->GetGeometryCRC();
2012-11-26 18:58:24 +00:00
break;
// RB begin
case idMapPrimitive::TYPE_MESH:
crc ^= static_cast<MapPolygonMesh*>( mapPrim )->GetGeometryCRC();
break;
// RB end
2012-11-26 18:58:24 +00:00
}
}
2012-11-26 18:58:24 +00:00
return crc;
}
/*
===============
idMapFile::Parse
===============
*/
bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
{
2012-11-26 18:58:24 +00:00
// no string concatenation for epairs and allow path names for materials
idLexer src( LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
idToken token;
idStr fullName;
idMapEntity* mapEnt;
2012-11-26 18:58:24 +00:00
int i, j, k;
2012-11-26 18:58:24 +00:00
name = filename;
name.StripFileExtension();
fullName = name;
hasPrimitiveData = false;
if( !ignoreRegion )
{
2012-11-26 18:58:24 +00:00
// try loading a .reg file first
fullName.SetFileExtension( "reg" );
src.LoadFile( fullName, osPath );
}
if( !src.IsLoaded() )
{
2012-11-26 18:58:24 +00:00
// now try a .map file
fullName.SetFileExtension( "map" );
src.LoadFile( fullName, osPath );
if( !src.IsLoaded() )
{
2012-11-26 18:58:24 +00:00
// didn't get anything at all
return false;
}
}
2012-11-26 18:58:24 +00:00
version = OLD_MAP_VERSION;
fileTime = src.GetFileTime();
entities.DeleteContents( true );
if( src.CheckTokenString( "Version" ) )
{
2012-11-26 18:58:24 +00:00
src.ReadTokenOnLine( &token );
version = token.GetFloatValue();
}
while( 1 )
{
2012-11-26 18:58:24 +00:00
mapEnt = idMapEntity::Parse( src, ( entities.Num() == 0 ), version );
if( !mapEnt )
{
2012-11-26 18:58:24 +00:00
break;
}
entities.Append( mapEnt );
}
2012-11-26 18:58:24 +00:00
SetGeometryCRC();
2012-11-26 18:58:24 +00:00
// if the map has a worldspawn
if( entities.Num() )
{
2012-11-26 18:58:24 +00:00
// "removeEntities" "classname" can be set in the worldspawn to remove all entities with the given classname
const idKeyValue* removeEntities = entities[0]->epairs.MatchPrefix( "removeEntities", NULL );
while( removeEntities )
{
2012-11-26 18:58:24 +00:00
RemoveEntities( removeEntities->GetValue() );
removeEntities = entities[0]->epairs.MatchPrefix( "removeEntities", removeEntities );
}
2012-11-26 18:58:24 +00:00
// "overrideMaterial" "material" can be set in the worldspawn to reset all materials
idStr material;
if( entities[0]->epairs.GetString( "overrideMaterial", "", material ) )
{
for( i = 0; i < entities.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
mapEnt = entities[i];
for( j = 0; j < mapEnt->GetNumPrimitives(); j++ )
{
idMapPrimitive* mapPrimitive = mapEnt->GetPrimitive( j );
switch( mapPrimitive->GetType() )
{
case idMapPrimitive::TYPE_BRUSH:
{
idMapBrush* mapBrush = static_cast<idMapBrush*>( mapPrimitive );
for( k = 0; k < mapBrush->GetNumSides(); k++ )
{
2012-11-26 18:58:24 +00:00
mapBrush->GetSide( k )->SetMaterial( material );
}
break;
}
case idMapPrimitive::TYPE_PATCH:
{
static_cast<idMapPatch*>( mapPrimitive )->SetMaterial( material );
2012-11-26 18:58:24 +00:00
break;
}
}
}
}
}
2012-11-26 18:58:24 +00:00
// force all entities to have a name key/value pair
if( entities[0]->epairs.GetBool( "forceEntityNames" ) )
{
for( i = 1; i < entities.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
mapEnt = entities[i];
if( !mapEnt->epairs.FindKey( "name" ) )
{
2012-11-26 18:58:24 +00:00
mapEnt->epairs.Set( "name", va( "%s%d", mapEnt->epairs.GetString( "classname", "forcedName" ), i ) );
}
}
}
2012-11-26 18:58:24 +00:00
// move the primitives of any func_group entities to the worldspawn
if( entities[0]->epairs.GetBool( "moveFuncGroups" ) )
{
for( i = 1; i < entities.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
mapEnt = entities[i];
if( idStr::Icmp( mapEnt->epairs.GetString( "classname" ), "func_group" ) == 0 )
{
2012-11-26 18:58:24 +00:00
entities[0]->primitives.Append( mapEnt->primitives );
mapEnt->primitives.Clear();
}
}
}
}
2012-11-26 18:58:24 +00:00
hasPrimitiveData = true;
return true;
}
/*
============
idMapFile::Write
============
*/
bool idMapFile::Write( const char* fileName, const char* ext, bool fromBasePath )
{
2012-11-26 18:58:24 +00:00
int i;
idStr qpath;
idFile* fp;
2012-11-26 18:58:24 +00:00
qpath = fileName;
qpath.SetFileExtension( ext );
2012-11-26 18:58:24 +00:00
idLib::common->Printf( "writing %s...\n", qpath.c_str() );
if( fromBasePath )
{
2012-11-26 18:58:24 +00:00
fp = idLib::fileSystem->OpenFileWrite( qpath, "fs_basepath" );
}
else
{
2012-11-26 18:58:24 +00:00
fp = idLib::fileSystem->OpenExplicitFileWrite( qpath );
}
if( !fp )
{
2012-11-26 18:58:24 +00:00
idLib::common->Warning( "Couldn't open %s\n", qpath.c_str() );
return false;
}
fp->WriteFloatString( "Version %f\n", ( float ) CURRENT_MAP_VERSION );
for( i = 0; i < entities.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
entities[i]->Write( fp, i );
}
2012-11-26 18:58:24 +00:00
idLib::fileSystem->CloseFile( fp );
2012-11-26 18:58:24 +00:00
return true;
}
/*
===============
idMapFile::SetGeometryCRC
===============
*/
void idMapFile::SetGeometryCRC()
{
2012-11-26 18:58:24 +00:00
int i;
2012-11-26 18:58:24 +00:00
geometryCRC = 0;
for( i = 0; i < entities.Num(); i++ )
{
2012-11-26 18:58:24 +00:00
geometryCRC ^= entities[i]->GetGeometryCRC();
}
}
/*
===============
idMapFile::AddEntity
===============
*/
int idMapFile::AddEntity( idMapEntity* mapEnt )
{
2012-11-26 18:58:24 +00:00
int ret = entities.Append( mapEnt );
return ret;
}
/*
===============
idMapFile::FindEntity
===============
*/
idMapEntity* idMapFile::FindEntity( const char* name )
{
for( int i = 0; i < entities.Num(); i++ )
{
idMapEntity* ent = entities[i];
if( idStr::Icmp( ent->epairs.GetString( "name" ), name ) == 0 )
{
2012-11-26 18:58:24 +00:00
return ent;
}
}
return NULL;
}
/*
===============
idMapFile::RemoveEntity
===============
*/
void idMapFile::RemoveEntity( idMapEntity* mapEnt )
{
2012-11-26 18:58:24 +00:00
entities.Remove( mapEnt );
delete mapEnt;
}
/*
===============
idMapFile::RemoveEntity
===============
*/
void idMapFile::RemoveEntities( const char* classname )
{
for( int i = 0; i < entities.Num(); i++ )
{
idMapEntity* ent = entities[i];
if( idStr::Icmp( ent->epairs.GetString( "classname" ), classname ) == 0 )
{
2012-11-26 18:58:24 +00:00
delete entities[i];
entities.RemoveIndex( i );
i--;
}
}
}
/*
===============
idMapFile::RemoveAllEntities
===============
*/
void idMapFile::RemoveAllEntities()
{
2012-11-26 18:58:24 +00:00
entities.DeleteContents( true );
hasPrimitiveData = false;
}
/*
===============
idMapFile::RemovePrimitiveData
===============
*/
void idMapFile::RemovePrimitiveData()
{
for( int i = 0; i < entities.Num(); i++ )
{
idMapEntity* ent = entities[i];
2012-11-26 18:58:24 +00:00
ent->RemovePrimitiveData();
}
hasPrimitiveData = false;
}
/*
===============
idMapFile::NeedsReload
===============
*/
bool idMapFile::NeedsReload()
{
if( name.Length() )
{
2012-11-26 18:58:24 +00:00
ID_TIME_T time = FILE_NOT_FOUND_TIMESTAMP;
if( idLib::fileSystem->ReadFile( name, NULL, &time ) > 0 )
{
2012-11-26 18:58:24 +00:00
return ( time > fileTime );
}
}
return true;
}
// RB begin
MapPolygonMesh::MapPolygonMesh()
{
type = TYPE_MESH;
polygons.Resize( 8, 4 );
contents = CONTENTS_SOLID;
opaque = true;
}
void MapPolygonMesh::ConvertFromBrush( const idMapBrush* mapBrush, int entityNum, int primitiveNum )
{
// fix degenerate planes
idPlane* planes = ( idPlane* ) _alloca16( mapBrush->GetNumSides() * sizeof( planes[0] ) );
for( int i = 0; i < mapBrush->GetNumSides(); i++ )
{
planes[i] = mapBrush->GetSide( i )->GetPlane();
planes[i].FixDegeneracies( DEGENERATE_DIST_EPSILON );
}
idList<idFixedWinding> planeWindings;
idBounds bounds;
bounds.Clear();
int numVerts = 0;
int numIndexes = 0;
bool badBrush = false;
for( int i = 0; i < mapBrush->GetNumSides(); i++ )
{
idMapBrushSide* mapSide = mapBrush->GetSide( i );
const idMaterial* material = declManager->FindMaterial( mapSide->GetMaterial() );
//contents |= ( material->GetContentFlags() & CONTENTS_REMOVE_UTIL );
//materials.AddUnique( material );
// chop base plane by other brush sides
idFixedWinding& w = planeWindings.Alloc();
w.BaseForPlane( -planes[i] );
if( !w.GetNumPoints() )
{
common->Printf( "Entity %i, Brush %i: base winding has no points\n", entityNum, primitiveNum );
badBrush = true;
break;
}
for( int j = 0; j < mapBrush->GetNumSides() && w.GetNumPoints(); j++ )
{
if( i == j )
{
continue;
}
if( !w.ClipInPlace( -planes[j], 0 ) )
{
// no intersection
//badBrush = true;
common->Printf( "Entity %i, Brush %i: no intersection with other brush plane\n", entityNum, primitiveNum );
//break;
}
}
if( w.GetNumPoints() <= 2 )
{
continue;
}
// only used for debugging
for( int j = 0; j < w.GetNumPoints(); j++ )
{
const idVec3& v = w[j].ToVec3();
bounds.AddPoint( v );
}
}
if( badBrush )
{
//common->Error( "" )
return;
}
// copy the data from the windings and build polygons
for( int i = 0; i < mapBrush->GetNumSides(); i++ )
{
idMapBrushSide* mapSide = mapBrush->GetSide( i );
idFixedWinding& w = planeWindings[i];
if( !w.GetNumPoints() )
{
continue;
}
MapPolygon* polygon = new MapPolygon();
polygon->SetMaterial( mapSide->GetMaterial() );
//for( int j = 0; j < w.GetNumPoints(); j++ )
// reverse order, so normal does not point inwards
for( int j = w.GetNumPoints() - 1; j >= 0; j-- )
{
polygon->AddIndex( verts.Num() + j );
}
polygons.Append( polygon );
for( int j = 0; j < w.GetNumPoints(); j++ )
{
idDrawVert& dv = verts.Alloc();
const idVec3& xyz = w[j].ToVec3();
dv.xyz = xyz;
// calculate texture s/t from brush primitive texture matrix
idVec4 texVec[2];
mapSide->GetTextureVectors( texVec );
idVec2 st;
st.x = ( xyz * texVec[0].ToVec3() ) + texVec[0][3];
st.y = ( xyz * texVec[1].ToVec3() ) + texVec[1][3];
// flip y
//st.y = 1.0f - st.y;
dv.SetTexCoord( st );
// copy normal
dv.SetNormal( mapSide->GetPlane().Normal() );
//if( dv->GetNormal().Length() < 0.9 || dv->GetNormal().Length() > 1.1 )
//{
// common->Error( "Bad normal in TriListForSide" );
//}
}
}
SetContents();
}
void MapPolygonMesh::ConvertFromPatch( const idMapPatch* patch, int entityNum, int primitiveNum )
{
idSurface_Patch* cp = new idSurface_Patch( *patch );
if( patch->GetExplicitlySubdivided() )
{
cp->SubdivideExplicit( patch->GetHorzSubdivisions(), patch->GetVertSubdivisions(), true );
}
else
{
cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
}
for( int i = 0; i < cp->GetNumIndexes(); i += 3 )
{
MapPolygon* polygon = new MapPolygon;
polygon->SetMaterial( patch->GetMaterial() );
idDrawVert& dv0 = verts.Alloc();
idDrawVert& dv1 = verts.Alloc();
idDrawVert& dv2 = verts.Alloc();
dv0 = ( *cp )[cp->GetIndexes()[i + 1]];
dv1 = ( *cp )[cp->GetIndexes()[i + 2]];
dv2 = ( *cp )[cp->GetIndexes()[i + 0]];
polygon->AddIndex( i + 0 );
polygon->AddIndex( i + 1 );
polygon->AddIndex( i + 2 );
polygons.Append( polygon );
}
delete cp;
SetContents();
}
bool MapPolygonMesh::Write( idFile* fp, int primitiveNum, const idVec3& origin ) const
{
fp->WriteFloatString( "// primitive %d\n{\n meshDef\n {\n", primitiveNum );
//fp->WriteFloatString( " \"%s\"\n ( %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight() );
fp->WriteFloatString( " ( %d %d 0 0 0 )\n", verts.Num(), polygons.Num() );
fp->WriteFloatString( " (\n" );
idVec2 st;
idVec3 n;
for( int i = 0; i < verts.Num(); i++ )
{
const idDrawVert* v = &verts[ i ];
st = v->GetTexCoord();
n = v->GetNormalRaw();
//fp->WriteFloatString( " ( %f %f %f %f %f %f %f %f )\n", v->xyz[0] + origin[0], v->xyz[1] + origin[1], v->xyz[2] + origin[2], st[0], st[1], n[0], n[1], n[2] );
fp->WriteFloatString( " ( %f %f %f %f %f %f %f %f )\n", v->xyz[0], v->xyz[1], v->xyz[2], st[0], st[1], n[0], n[1], n[2] );
}
fp->WriteFloatString( " )\n" );
fp->WriteFloatString( " (\n" );
for( int i = 0; i < polygons.Num(); i++ )
{
MapPolygon* poly = polygons[ i ];
fp->WriteFloatString( " \"%s\" %d = ", poly->GetMaterial(), poly->indexes.Num() );
for( int j = 0; j < poly->indexes.Num(); j++ )
{
fp->WriteFloatString( "%d ", poly->indexes[j] );
}
fp->WriteFloatString( "\n" );
}
fp->WriteFloatString( " )\n" );
fp->WriteFloatString( " }\n}\n" );
return true;
}
MapPolygonMesh* MapPolygonMesh::Parse( idLexer& src, const idVec3& origin, float version )
{
float info[7];
idToken token;
int i;
if( !src.ExpectTokenString( "{" ) )
{
return NULL;
}
// Parse it
if( !src.Parse1DMatrix( 5, info ) )
{
src.Error( "MapPolygonMesh::Parse: unable to parse meshDef info" );
return NULL;
}
const int numVertices = ( int ) info[0];
const int numPolygons = ( int ) info[1];
MapPolygonMesh* mesh = new MapPolygonMesh();
// parse vertices
if( !src.ExpectTokenString( "(" ) )
{
src.Error( "MapPolygonMesh::Parse: bad mesh vertex data" );
delete mesh;
return NULL;
}
for( i = 0; i < numVertices; i++ )
{
float v[8];
if( !src.Parse1DMatrix( 8, v ) )
{
src.Error( "MapPolygonMesh::Parse: bad vertex column data" );
delete mesh;
return NULL;
}
// TODO optimize: preallocate vertices
//vert = &( ( *patch )[i * patch->GetWidth() + j] );
idDrawVert vert;
vert.xyz[0] = v[0];// - origin[0];
vert.xyz[1] = v[1];// - origin[1];
vert.xyz[2] = v[2];// - origin[2];
vert.SetTexCoord( v[3], v[4] );
idVec3 n( v[5], v[6], v[7] );
vert.SetNormal( n );
mesh->AddVertex( vert );
}
if( !src.ExpectTokenString( ")" ) )
{
delete mesh;
src.Error( "MapPolygonMesh::Parse: unable to parse vertices" );
return NULL;
}
// parse polygons
if( !src.ExpectTokenString( "(" ) )
{
src.Error( "MapPolygonMesh::Parse: bad mesh polygon data" );
delete mesh;
return NULL;
}
for( i = 0; i < numPolygons; i++ )
{
// get material name
MapPolygon* polygon = new MapPolygon();
mesh->AddPolygon( polygon );
src.ReadToken( &token );
if( token.type == TT_STRING )
{
polygon->SetMaterial( token );;
}
else
{
src.Error( "MapPolygonMesh::Parse: bad mesh polygon data" );
delete mesh;
return NULL;
}
int numIndexes = src.ParseInt();
if( !src.ExpectTokenString( "=" ) )
{
src.Error( "MapPolygonMesh::Parse: bad mesh polygon data" );
delete mesh;
return NULL;
}
//idTempArray<int> indexes( numIndexes );
for( int j = 0; j < numIndexes; j++ )
{
//indexes[j] = src.ParseInt();
int index = src.ParseInt();
polygon->AddIndex( index );
}
//polygon->SetIndexes( indexes );
}
if( !src.ExpectTokenString( ")" ) )
{
delete mesh;
src.Error( "MapPolygonMesh::Parse: unable to parse polygons" );
return NULL;
}
if( !src.ExpectTokenString( "}" ) )
{
delete mesh;
src.Error( "MapPolygonMesh::Parse: unable to parse mesh primitive end" );
return NULL;
}
if( !src.ExpectTokenString( "}" ) )
{
delete mesh;
src.Error( "MapPolygonMesh::Parse: unable to parse mesh primitive end" );
return NULL;
}
mesh->SetContents();
return mesh;
}
void MapPolygonMesh::SetContents()
{
if( polygons.Num() < 1 )
{
contents = CONTENTS_SOLID;
opaque = true;
return;
}
int c2;
MapPolygon* poly = polygons[0];
const idMaterial* mat = declManager->FindMaterial( poly->GetMaterial() );
contents = mat->GetContentFlags();
//b->contentShader = s->material;
bool mixed = false;
// a brush is only opaque if all sides are opaque
opaque = true;
for( int i = 1 ; i < polygons.Num() ; i++ )
{
poly = polygons[i];
const idMaterial* mat2 = declManager->FindMaterial( poly->GetMaterial() );
c2 = mat2->GetContentFlags();
if( c2 != contents )
{
mixed = true;
contents |= c2;
}
if( mat2->Coverage() != MC_OPAQUE )
{
opaque = false;
}
}
}
unsigned int MapPolygonMesh::GetGeometryCRC() const
{
int i;
MapPolygon* poly;
unsigned int crc;
crc = 0;
for( i = 0; i < verts.Num(); i++ )
{
crc ^= FloatCRC( verts[i].xyz.x );
crc ^= FloatCRC( verts[i].xyz.y );
crc ^= FloatCRC( verts[i].xyz.z );
}
for( i = 0; i < polygons.Num(); i++ )
{
poly = polygons[i];
crc ^= StringCRC( poly->GetMaterial() );
}
return crc;
}
bool MapPolygonMesh::IsAreaportal() const
{
return ( ( contents & CONTENTS_AREAPORTAL ) != 0 );
}
void MapPolygonMesh::GetBounds( idBounds& bounds ) const
{
if( !verts.Num() )
{
bounds.Clear();
return;
}
bounds[0] = bounds[1] = verts[0].xyz;
for( int i = 1; i < verts.Num(); i++ )
{
const idVec3& p = verts[i].xyz;
if( p.x < bounds[0].x )
{
bounds[0].x = p.x;
}
else if( p.x > bounds[1].x )
{
bounds[1].x = p.x;
}
if( p.y < bounds[0].y )
{
bounds[0].y = p.y;
}
else if( p.y > bounds[1].y )
{
bounds[1].y = p.y;
}
if( p.z < bounds[0].z )
{
bounds[0].z = p.z;
}
else if( p.z > bounds[1].z )
{
bounds[1].z = p.z;
}
}
}
bool idMapFile::ConvertToPolygonMeshFormat()
{
int count = GetNumEntities();
for( int j = 0; j < count; j++ )
{
idMapEntity* ent = GetEntity( j );
if( ent )
{
idStr classname = ent->epairs.GetString( "classname" );
//if( classname == "worldspawn" )
{
for( int i = 0; i < ent->GetNumPrimitives(); i++ )
{
idMapPrimitive* mapPrim;
mapPrim = ent->GetPrimitive( i );
if( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH )
{
MapPolygonMesh* meshPrim = new MapPolygonMesh();
meshPrim->epairs.Copy( mapPrim->epairs );
meshPrim->ConvertFromBrush( static_cast<idMapBrush*>( mapPrim ), j, i );
ent->primitives[ i ] = meshPrim;
delete mapPrim;
continue;
}
#if 0
else if( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH )
{
MapPolygonMesh* meshPrim = new MapPolygonMesh();
meshPrim->epairs.Copy( mapPrim->epairs );
meshPrim->ConvertFromPatch( static_cast<idMapPatch*>( mapPrim ), j, i );
ent->primitives[ i ] = meshPrim;
delete mapPrim;
continue;
}
#endif
}
}
}
}
return true;
}
// RB end