2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
2012-11-28 15:47:07 +00:00
|
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
2022-01-07 17:46:35 +00:00
|
|
|
Copyright (C) 2015-2022 Robert Beckebans
|
|
|
|
Copyright (C) 2020 Admer (id Tech Fox)
|
2012-11-26 18:58:24 +00:00
|
|
|
|
2012-11-28 15:47:07 +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
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
#include "../renderer/Image.h"
|
2012-11-26 18:58:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
FloatCRC
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
ID_INLINE unsigned int FloatCRC( float f )
|
|
|
|
{
|
|
|
|
return *( unsigned int* )&f;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
StringCRC
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
ID_INLINE unsigned int StringCRC( const char* str )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
unsigned int i, crc;
|
2012-11-28 15:47:07 +00:00
|
|
|
const unsigned char* ptr;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
crc = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
|
=================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
static void ComputeAxisBase( const idVec3& normal, idVec3& texS, idVec3& texT )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
float RotY, RotZ;
|
|
|
|
idVec3 n;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
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];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
2012-11-28 15:47:07 +00:00
|
|
|
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 )
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
|
=================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idMapBrushSide::GetTextureVectors( idVec4 v[2] ) const
|
|
|
|
{
|
2021-02-13 17:46:34 +00:00
|
|
|
if( projection == PROJECTION_VALVE220 )
|
2012-11-28 15:47:07 +00:00
|
|
|
{
|
2021-03-12 17:13:33 +00:00
|
|
|
v[0][0] = texValve[0][0] * ( 1.0f / texScale[0] );
|
|
|
|
v[0][1] = texValve[0][1] * ( 1.0f / texScale[0] );
|
|
|
|
v[0][2] = texValve[0][2] * ( 1.0f / texScale[0] );
|
|
|
|
v[0][3] = texValve[0][3];
|
|
|
|
|
|
|
|
v[1][0] = texValve[1][0] * ( 1.0f / texScale[1] );
|
|
|
|
v[1][1] = texValve[1][1] * ( 1.0f / texScale[1] );
|
|
|
|
v[1][2] = texValve[1][2] * ( 1.0f / texScale[1] );
|
|
|
|
v[1][3] = texValve[1][3];
|
2021-02-13 17:46:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
idVec3 texX, texY;
|
|
|
|
|
|
|
|
ComputeAxisBase( plane.Normal(), texX, texY );
|
|
|
|
for( int i = 0; i < 2; i++ )
|
|
|
|
{
|
|
|
|
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() );
|
|
|
|
}
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
// RB begin
|
|
|
|
inline bool BrushPrimitive_Degenerate( const idVec3& bpTexMatX, const idVec3& bpTexMatY )
|
|
|
|
{
|
|
|
|
// 2D cross product
|
|
|
|
return ( bpTexMatX[0] * bpTexMatY[1] - bpTexMatX[1] * bpTexMatY[0] ) == 0;
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:30:49 +00:00
|
|
|
// heavily inspired by Valve220_from_BP from Netradiant-custom
|
2022-01-21 17:33:42 +00:00
|
|
|
void idMapBrushSide::ConvertToValve220Format( const idMat4& entityTransform, idStrList& textureCollections )
|
2021-11-09 18:47:06 +00:00
|
|
|
{
|
|
|
|
// create p1, p2, p3
|
|
|
|
idVec3 forward = plane.Normal();
|
|
|
|
idVec3 p1 = forward * plane.Dist();
|
|
|
|
|
|
|
|
// create tangents right,up similar as in Quake's MakeNormalVectors
|
|
|
|
idVec3 right = forward;
|
|
|
|
right[1] = -forward[0];
|
|
|
|
right[2] = forward[1];
|
|
|
|
right[0] = forward[2];
|
|
|
|
|
|
|
|
float d = right * forward;
|
|
|
|
right = right + ( -d * forward );
|
|
|
|
right.Normalize();
|
|
|
|
|
|
|
|
idVec3 up = right.Cross( forward );
|
|
|
|
|
|
|
|
// offset p1 by tangents to have 3 points in a plane
|
|
|
|
idVec3 p2 = p1 + right;
|
|
|
|
idVec3 p3 = p1 + up;
|
|
|
|
|
|
|
|
// move planepts from entity space to world space because TrenchBroom can only handle brushes in world space
|
|
|
|
planepts[0] = entityTransform * p1;
|
|
|
|
planepts[1] = entityTransform * p2;
|
|
|
|
planepts[2] = entityTransform * p3;
|
|
|
|
|
|
|
|
idVec3 texX, texY;
|
|
|
|
|
|
|
|
ComputeAxisBase( plane.Normal(), texX, texY );
|
|
|
|
|
|
|
|
texValve[0][0] = texX[0];
|
|
|
|
texValve[0][1] = texX[1];
|
|
|
|
texValve[0][2] = texX[2];
|
|
|
|
|
|
|
|
texValve[1][0] = texY[0];
|
|
|
|
texValve[1][1] = texY[1];
|
|
|
|
texValve[1][2] = texY[2];
|
|
|
|
|
|
|
|
texScale[0] = 1.0f;
|
|
|
|
texScale[1] = 1.0f;
|
|
|
|
|
|
|
|
if( BrushPrimitive_Degenerate( texX, texY ) )
|
|
|
|
{
|
|
|
|
//idLib::Warning( "non orthogonal texture matrix in ConvertToValve220Format" );
|
|
|
|
}
|
|
|
|
|
|
|
|
// rotate initial axes
|
|
|
|
for( int i = 0; i < 2; i++ )
|
|
|
|
{
|
|
|
|
texValve[i][0] = texX[0] * texMat[i][0] + texY[0] * texMat[i][1];
|
|
|
|
texValve[i][1] = texX[1] * texMat[i][0] + texY[1] * texMat[i][1];
|
|
|
|
texValve[i][2] = texX[2] * texMat[i][0] + texY[2] * texMat[i][1];
|
|
|
|
//texValve[i][3] = texMat[i][2] + ( origin * texValve[i].ToVec3() );
|
2021-11-09 20:30:49 +00:00
|
|
|
|
|
|
|
texValve[i][3] = 0;
|
|
|
|
texValve[i].Normalize();
|
2021-11-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
|
2022-01-21 17:33:42 +00:00
|
|
|
idMapFile::AddMaterialToCollection( GetMaterial(), textureCollections );
|
2021-11-09 18:47:06 +00:00
|
|
|
|
|
|
|
const idMaterial* material = declManager->FindMaterial( GetMaterial() );
|
|
|
|
|
|
|
|
idImage* image = material->GetEditorImage();
|
|
|
|
if( image != NULL )
|
|
|
|
{
|
|
|
|
texSize.x = image->GetUploadWidth();
|
|
|
|
texSize.y = image->GetUploadHeight();
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:30:49 +00:00
|
|
|
// remove texture dimensions from texMat
|
|
|
|
idVec3 localMat[2];
|
|
|
|
localMat[0] = texMat[0] * texSize.x;
|
|
|
|
localMat[1] = texMat[1] * texSize.y;
|
|
|
|
|
|
|
|
// from DoomEdit TexMatToFakeTexCoords
|
2021-11-09 18:47:06 +00:00
|
|
|
// compute a fake shift scale rot representation from the texture matrix
|
|
|
|
// these shift scale rot values are to be understood in the local axis base
|
2021-11-09 20:30:49 +00:00
|
|
|
texScale[0] = 1.0f / idMath::Sqrt( localMat[0][0] * localMat[0][0] + localMat[1][0] * localMat[1][0] );
|
|
|
|
texScale[1] = 1.0f / idMath::Sqrt( localMat[0][1] * localMat[0][1] + localMat[1][1] * localMat[1][1] );
|
2021-11-09 18:47:06 +00:00
|
|
|
|
|
|
|
if( texMat[0][0] < idMath::FLOAT_EPSILON )
|
|
|
|
{
|
2021-11-09 20:30:49 +00:00
|
|
|
texValve[0] = -texValve[0];
|
2021-11-09 18:47:06 +00:00
|
|
|
texScale[0] = -texScale[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if( texMat[1][0] < idMath::FLOAT_EPSILON )
|
|
|
|
{
|
2021-11-09 20:30:49 +00:00
|
|
|
texValve[1] = -texValve[1];
|
2021-11-09 18:47:06 +00:00
|
|
|
texScale[1] = -texScale[1];
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:30:49 +00:00
|
|
|
// shift
|
|
|
|
texValve[0][3] = localMat[0][2];
|
|
|
|
texValve[1][3] = localMat[1][2];
|
2021-11-16 21:11:27 +00:00
|
|
|
|
|
|
|
projection = idMapBrushSide::PROJECTION_VALVE220;
|
2021-11-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
=================
|
|
|
|
idMapPatch::Parse
|
|
|
|
=================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapPatch* idMapPatch::Parse( idLexer& src, const idVec3& origin, bool patchDef3, float version )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
float info[7];
|
2012-11-28 15:47:07 +00:00
|
|
|
idDrawVert* vert;
|
2012-11-26 18:58:24 +00:00
|
|
|
idToken token;
|
|
|
|
int i, j;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ExpectTokenString( "{" ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// read the material (we had an implicit 'textures/' in the old format...)
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapPatch::Parse: unexpected EOF" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// Parse it
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapPatch* patch = new( TAG_IDLIB ) idMapPatch( info[0], info[1] );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
patch->SetSize( info[0], info[1] );
|
2012-11-28 15:47:07 +00:00
|
|
|
if( version < 2.0f )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
patch->SetMaterial( "textures/" + token );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
patch->SetMaterial( token );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( patchDef3 )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
patch->SetHorzSubdivisions( info[2] );
|
|
|
|
patch->SetVertSubdivisions( info[3] );
|
|
|
|
patch->SetExplicitlySubdivided( true );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// these were written out in the wrong order, IMHO
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ExpectTokenString( "(" ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapPatch::Parse: bad patch vertex data" );
|
|
|
|
delete patch;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
for( i = 0; i < patch->GetHeight(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
float v[5];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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] );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// read any key/value pairs
|
2012-11-28 15:47:07 +00:00
|
|
|
while( src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
if( token == "}" )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.ExpectTokenString( "}" );
|
|
|
|
break;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return patch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
idMapPatch::Write
|
|
|
|
============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idMapPatch::Write( idFile* fp, int primitiveNum, const idVec3& origin ) const
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i, j;
|
2012-11-28 15:47:07 +00:00
|
|
|
const idDrawVert* v;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( GetExplicitlySubdivided() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( "// primitive %d\n{\n patchDef3\n {\n", primitiveNum );
|
2012-11-28 15:47:07 +00:00
|
|
|
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 );
|
2012-11-28 15:47:07 +00:00
|
|
|
fp->WriteFloatString( " \"%s\"\n ( %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight() );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( " (\n" );
|
|
|
|
idVec2 st;
|
2012-11-28 15:47:07 +00:00
|
|
|
for( i = 0; i < GetWidth(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( " ( " );
|
2012-11-28 15:47:07 +00:00
|
|
|
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],
|
2012-11-28 15:47:07 +00:00
|
|
|
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" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapPatch::GetGeometryCRC
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
unsigned int idMapPatch::GetGeometryCRC() const
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i, j;
|
|
|
|
unsigned int crc;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
crc = GetHorzSubdivisions() ^ GetVertSubdivisions();
|
2012-11-28 15:47:07 +00:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
crc ^= StringCRC( GetMaterial() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
idMapBrush::Parse
|
|
|
|
=================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapBrushSide* side;
|
2012-11-26 18:58:24 +00:00
|
|
|
idDict epairs;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ExpectTokenString( "{" ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapBrush::Parse: unexpected EOF" );
|
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( token == "}" )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// here we may have to jump over brush epairs ( only used in editor )
|
2012-11-28 15:47:07 +00:00
|
|
|
do
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// if token is a brace
|
2012-11-28 15:47:07 +00:00
|
|
|
if( token == "(" )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// the token should be a key string for a key/value pair
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
idStr key = token;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
epairs.Set( key, token );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// try to read the next key
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapBrush::Parse: unexpected EOF" );
|
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
while( 1 );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
src.UnreadToken( &token );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
side = new( TAG_IDLIB ) idMapBrushSide();
|
|
|
|
sides.Append( side );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// read the three point plane definition
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
planepts[0] -= origin;
|
|
|
|
planepts[1] -= origin;
|
|
|
|
planepts[2] -= origin;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
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
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// read the material
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// we had an implicit 'textures/' in the old format...
|
2012-11-28 15:47:07 +00:00
|
|
|
if( version < 2.0f )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
side->material = "textures/" + token;
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
side->material = token;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// Q2 allowed override of default flags and values, but we don't any more
|
2012-11-28 15:47:07 +00:00
|
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
|
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
|
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
while( 1 );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ExpectTokenString( "}" ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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] );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
brush->epairs = epairs;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return brush;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
idMapBrush::ParseQ3
|
|
|
|
=================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapBrushSide* side;
|
2012-11-26 18:58:24 +00:00
|
|
|
idDict epairs;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if( src.CheckTokenString( "}" ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
side = new( TAG_IDLIB ) idMapBrushSide();
|
2012-11-26 18:58:24 +00:00
|
|
|
sides.Append( side );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// read the three point plane definition
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
planepts[0] -= origin;
|
|
|
|
planepts[1] -= origin;
|
|
|
|
planepts[2] -= origin;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// read the material
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// we have an implicit 'textures/' in the old format
|
|
|
|
side->material = "textures/" + token;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
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;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// Q2 allowed override of default flags and values, but we don't any more
|
2012-11-28 15:47:07 +00:00
|
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
|
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
|
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
while( 1 );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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] );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
brush->epairs = epairs;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return brush;
|
|
|
|
}
|
|
|
|
|
2021-02-13 17:46:34 +00:00
|
|
|
/*
|
|
|
|
=================
|
|
|
|
idMapBrush::ParseValve220
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
idMapBrush* idMapBrush::ParseValve220( idLexer& src, const idVec3& origin )
|
|
|
|
{
|
|
|
|
float scale[2], rotate;
|
|
|
|
idVec3 planepts[3];
|
|
|
|
idToken token;
|
|
|
|
idList<idMapBrushSide*> sides;
|
|
|
|
idMapBrushSide* side;
|
|
|
|
idDict epairs;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if( src.CheckTokenString( "}" ) )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
side = new( TAG_IDLIB ) idMapBrushSide();
|
|
|
|
sides.Append( side );
|
|
|
|
|
|
|
|
// 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() ) )
|
|
|
|
{
|
2022-02-05 14:49:50 +00:00
|
|
|
src.Error( "idMapBrush::ParseValve220: unable to read brush side plane definition" );
|
2021-02-13 17:46:34 +00:00
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-03-12 17:13:33 +00:00
|
|
|
// backup source points
|
|
|
|
side->planepts[0] = planepts[0];
|
|
|
|
side->planepts[1] = planepts[1];
|
|
|
|
side->planepts[2] = planepts[2];
|
|
|
|
|
2021-02-13 17:46:34 +00:00
|
|
|
planepts[0] -= origin;
|
|
|
|
planepts[1] -= origin;
|
|
|
|
planepts[2] -= origin;
|
|
|
|
|
|
|
|
side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
|
|
|
|
|
|
|
|
// read the material
|
|
|
|
if( !src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
2022-02-05 14:49:50 +00:00
|
|
|
src.Error( "idMapBrush::ParseValve220: unable to read brush side material" );
|
2021-02-13 17:46:34 +00:00
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-02-05 14:49:50 +00:00
|
|
|
idToken matPrefix;
|
|
|
|
idToken numberToken;
|
|
|
|
if( token == "*" || token == "+" || token.type == TT_NUMBER )
|
|
|
|
{
|
|
|
|
// RB: try again for Quake 1 maps
|
|
|
|
|
|
|
|
matPrefix = token;
|
|
|
|
|
|
|
|
if( token == "+" )
|
|
|
|
{
|
|
|
|
if( !src.ReadTokenOnLine( &numberToken ) )
|
|
|
|
{
|
|
|
|
src.Error( "idMapBrush::ParseValve220: unable to read brush side material" );
|
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( numberToken.type == TT_NUMBER )
|
|
|
|
{
|
|
|
|
if( !src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "idMapBrush::ParseValve220: unable to read brush side material" );
|
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( !src.ReadTokenOnLine( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "idMapBrush::ParseValve220: unable to read brush side material" );
|
|
|
|
sides.DeleteContents( true );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-13 17:46:34 +00:00
|
|
|
// we have an implicit 'textures/' in the old format
|
2022-02-05 14:49:50 +00:00
|
|
|
if( numberToken.type == TT_NUMBER )
|
|
|
|
{
|
|
|
|
side->material = "textures/" + numberToken + token;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
side->material = "textures/" + token;
|
|
|
|
}
|
2021-02-13 17:46:34 +00:00
|
|
|
side->projection = idMapBrushSide::PROJECTION_VALVE220;
|
|
|
|
|
|
|
|
for( int axis = 0; axis < 2; axis++ )
|
|
|
|
{
|
|
|
|
src.ExpectTokenString( "[" );
|
|
|
|
|
|
|
|
for( int comp = 0; comp < 4; comp++ )
|
|
|
|
{
|
|
|
|
side->texValve[axis][comp] = src.ParseFloat();
|
|
|
|
}
|
|
|
|
|
|
|
|
src.ExpectTokenString( "]" );
|
|
|
|
}
|
|
|
|
|
|
|
|
// read the texture rotate and scale
|
|
|
|
rotate = src.ParseFloat();
|
|
|
|
|
|
|
|
scale[0] = src.ParseFloat();
|
|
|
|
scale[1] = src.ParseFloat();
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
/*
|
|
|
|
RB: negative values seem to be valid and the q3map2 implementation in netradiant-custom is faulty
|
2021-07-26 06:51:44 +00:00
|
|
|
if( scale[0] < idMath::FLOAT_EPSILON )
|
2021-02-13 17:46:34 +00:00
|
|
|
{
|
|
|
|
scale[0] = 1.0f;
|
|
|
|
}
|
2021-07-26 06:51:44 +00:00
|
|
|
if( scale[1] < idMath::FLOAT_EPSILON )
|
2021-02-13 17:46:34 +00:00
|
|
|
{
|
|
|
|
scale[1] = 1.0f;
|
|
|
|
}
|
2021-11-09 18:47:06 +00:00
|
|
|
*/
|
2021-02-13 17:46:34 +00:00
|
|
|
|
2021-03-12 17:13:33 +00:00
|
|
|
side->texScale[0] = scale[0];
|
|
|
|
side->texScale[1] = scale[1];
|
2021-02-13 17:46:34 +00:00
|
|
|
|
|
|
|
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 ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while( 1 );
|
|
|
|
|
|
|
|
idMapBrush* brush = new( TAG_IDLIB ) idMapBrush();
|
|
|
|
for( int i = 0; i < sides.Num(); i++ )
|
|
|
|
{
|
|
|
|
brush->AddSide( sides[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
brush->epairs = epairs;
|
|
|
|
|
|
|
|
return brush;
|
|
|
|
}
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
============
|
|
|
|
idMapBrush::Write
|
|
|
|
============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idMapBrush::Write( idFile* fp, int primitiveNum, const idVec3& origin ) const
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapBrushSide* side;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( "// primitive %d\n{\n brushDef3\n {\n", primitiveNum );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// write brush epairs
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// write brush sides
|
2012-11-28 15:47:07 +00:00
|
|
|
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",
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( " }\n}\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-03-12 17:13:33 +00:00
|
|
|
/*
|
|
|
|
============
|
|
|
|
RB idMapBrush::WriteValve220
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
bool idMapBrush::WriteValve220( idFile* fp, int primitiveNum, const idVec3& origin ) const
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
idMapBrushSide* side;
|
|
|
|
|
|
|
|
fp->WriteFloatString( "// brush %d\n{\n", primitiveNum );
|
|
|
|
|
|
|
|
// 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() );
|
|
|
|
}
|
|
|
|
|
|
|
|
// write brush sides
|
|
|
|
for( i = 0; i < GetNumSides(); i++ )
|
|
|
|
{
|
|
|
|
side = GetSide( i );
|
|
|
|
fp->WriteFloatString( "( %f %f %f ) ( %f %f %f ) ( %f %f %f )",
|
|
|
|
side->planepts[0][0], side->planepts[0][1], side->planepts[0][2],
|
|
|
|
side->planepts[1][0], side->planepts[1][1], side->planepts[1][2],
|
|
|
|
side->planepts[2][0], side->planepts[2][1], side->planepts[2][2] );
|
|
|
|
|
|
|
|
// strip off textures/
|
|
|
|
if( idStr::Icmpn( side->material.c_str(), "textures/", 9 ) == 0 )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( " %s ", side->material.c_str() + 9 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( " %s ", side->material.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
fp->WriteFloatString( "[ %f %f %f %f ] [ %f %f %f %f ] 0 %f %f 0 0 0\n",
|
|
|
|
side->texValve[0][0], side->texValve[0][1], side->texValve[0][2], side->texValve[0][3],
|
|
|
|
side->texValve[1][0], side->texValve[1][1], side->texValve[1][2], side->texValve[1][3],
|
|
|
|
side->texScale[0], side->texScale[1] );
|
|
|
|
}
|
|
|
|
|
|
|
|
fp->WriteFloatString( "}\n" );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapBrush::GetGeometryCRC
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
unsigned int idMapBrush::GetGeometryCRC() const
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i, j;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapBrushSide* mapSide;
|
2012-11-26 18:58:24 +00:00
|
|
|
unsigned int crc;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
crc = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
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() );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
2021-09-04 18:36:27 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapBrush::IsOriginBrush
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
bool idMapBrush::IsOriginBrush() const
|
|
|
|
{
|
2021-09-11 16:02:16 +00:00
|
|
|
for( int i = 0; i < GetNumSides(); i++ )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
|
|
|
const idMaterial* material = declManager->FindMaterial( sides[i]->GetMaterial() );
|
2021-09-11 16:02:16 +00:00
|
|
|
if( material && material->GetContentFlags() & CONTENTS_ORIGIN )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
idMapEntity::Parse
|
|
|
|
================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapEntity* idMapEntity::Parse( idLexer& src, bool worldSpawn, float version )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
idToken token;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapEntity* mapEnt;
|
|
|
|
idMapPatch* mapPatch;
|
|
|
|
idMapBrush* mapBrush;
|
2015-04-12 09:53:05 +00:00
|
|
|
// RB begin
|
|
|
|
MapPolygonMesh* mapMesh;
|
|
|
|
// RB end
|
2012-11-26 18:58:24 +00:00
|
|
|
bool worldent;
|
|
|
|
idVec3 origin;
|
|
|
|
double v1, v2, v3;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( token != "{" )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapEntity::Parse: { not found, found %s", token.c_str() );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
mapEnt = new( TAG_IDLIB ) idMapEntity();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( worldSpawn )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
mapEnt->primitives.Resize( 1024, 256 );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
origin.Zero();
|
|
|
|
worldent = false;
|
2012-11-28 15:47:07 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapEntity::Parse: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( token == "}" )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( token == "{" )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// parse a brush or patch
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.Error( "idMapEntity::Parse: unexpected EOF" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( worldent )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
origin.Zero();
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// if is it a brush: brush, brushDef, brushDef2, brushDef3
|
2012-11-28 15:47:07 +00:00
|
|
|
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 );
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !mapBrush )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mapEnt->AddPrimitive( mapBrush );
|
|
|
|
}
|
|
|
|
// if is it a patch: patchDef2, patchDef3
|
2012-11-28 15:47:07 +00:00
|
|
|
else if( token.Icmpn( "patch", 5 ) == 0 )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
mapPatch = idMapPatch::Parse( src, origin, !token.Icmp( "patchDef3" ), version );
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !mapPatch )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mapEnt->AddPrimitive( mapPatch );
|
|
|
|
}
|
2015-04-12 09:53:05 +00:00
|
|
|
// 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
|
2021-02-13 17:46:34 +00:00
|
|
|
// assume it's a brush in Valve 220 style from TrenchBroom
|
2012-11-28 15:47:07 +00:00
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
src.UnreadToken( &token );
|
2021-02-13 17:46:34 +00:00
|
|
|
mapBrush = idMapBrush::ParseValve220( src, origin );
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !mapBrush )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mapEnt->AddPrimitive( mapBrush );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
idStr key, value;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// parse a key / value pair
|
|
|
|
key = token;
|
|
|
|
src.ReadTokenOnLine( &token );
|
|
|
|
value = token;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// strip trailing spaces that sometimes get accidentally
|
|
|
|
// added in the editor
|
|
|
|
value.StripTrailingWhitespace();
|
|
|
|
key.StripTrailingWhitespace();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
mapEnt->epairs.Set( key, value );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
else if( !idStr::Icmp( key, "classname" ) && !idStr::Icmp( value, "worldspawn" ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
worldent = true;
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
while( 1 );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2021-09-04 18:36:27 +00:00
|
|
|
mapEnt->CalculateBrushOrigin();
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return mapEnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
idMapEntity::Write
|
|
|
|
============
|
|
|
|
*/
|
2021-03-12 17:13:33 +00:00
|
|
|
bool idMapEntity::Write( idFile* fp, int entityNum, bool valve220 ) const
|
2012-11-28 15:47:07 +00:00
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapPrimitive* mapPrim;
|
2012-11-26 18:58:24 +00:00
|
|
|
idVec3 origin;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( "// entity %d\n{\n", entityNum );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// write entity epairs
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
epairs.GetVector( "origin", "0 0 0", origin );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// write pritimives
|
2012-11-28 15:47:07 +00:00
|
|
|
for( i = 0; i < GetNumPrimitives(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
mapPrim = GetPrimitive( i );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
switch( mapPrim->GetType() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
case idMapPrimitive::TYPE_BRUSH:
|
2021-03-12 17:13:33 +00:00
|
|
|
if( valve220 )
|
|
|
|
{
|
|
|
|
static_cast<idMapBrush*>( mapPrim )->WriteValve220( fp, i, origin );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
static_cast<idMapBrush*>( mapPrim )->Write( fp, i, origin );
|
|
|
|
}
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
case idMapPrimitive::TYPE_PATCH:
|
2012-11-28 15:47:07 +00:00
|
|
|
static_cast<idMapPatch*>( mapPrim )->Write( fp, i, origin );
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
2015-04-12 09:53:05 +00:00
|
|
|
// 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
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
fp->WriteFloatString( "}\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// RB begin
|
|
|
|
bool idMapEntity::WriteJSON( idFile* fp, int entityNum, int numEntities ) const
|
|
|
|
{
|
|
|
|
idVec3 origin;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t{\n\t\t\t\"entity\": \"%d\",\n", entityNum );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
idStr key;
|
|
|
|
idStr value;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
for( int i = 0; i < epairs.GetNumKeyVals(); i++ )
|
|
|
|
{
|
|
|
|
key = epairs.GetKeyVal( i )->GetKey();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
key.ReplaceChar( '\t', ' ' );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
value = epairs.GetKeyVal( i )->GetValue();
|
|
|
|
value.BackSlashesToSlashes();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t\t\"%s\": \"%s\"%s\n", key.c_str(), value.c_str(), ( ( i == ( epairs.GetNumKeyVals() - 1 ) ) && !GetNumPrimitives() ) ? "" : "," );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
epairs.GetVector( "origin", "0 0 0", origin );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// write pritimives
|
|
|
|
if( GetNumPrimitives() )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "\t\t\t\"primitives\":\n\t\t\t[\n" );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
int numPrimitives = GetNumPrimitives();
|
|
|
|
for( int i = 0; i < numPrimitives; i++ )
|
|
|
|
{
|
|
|
|
idMapPrimitive* mapPrim = GetPrimitive( i );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
switch( mapPrim->GetType() )
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
case idMapPrimitive::TYPE_BRUSH:
|
|
|
|
static_cast<idMapBrush*>( mapPrim )->Write( fp, i, origin );
|
|
|
|
break;
|
|
|
|
case idMapPrimitive::TYPE_PATCH:
|
|
|
|
static_cast<idMapPatch*>( mapPrim )->Write( fp, i, origin );
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case idMapPrimitive::TYPE_MESH:
|
|
|
|
static_cast<MapPolygonMesh*>( mapPrim )->WriteJSON( fp, i, origin );
|
|
|
|
break;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// find next mesh primitive
|
|
|
|
idMapPrimitive* nextPrim = NULL;
|
|
|
|
for( int j = i + 1; j < numPrimitives; j++ )
|
|
|
|
{
|
|
|
|
nextPrim = GetPrimitive( j );
|
|
|
|
if( nextPrim->GetType() == idMapPrimitive::TYPE_MESH )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( nextPrim && ( nextPrim->GetType() == idMapPrimitive::TYPE_MESH ) )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( ",\n" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "\n" );
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( GetNumPrimitives() )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "\t\t\t]\n" );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t}%s\n", ( entityNum == ( numEntities - 1 ) ) ? "" : "," );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
idMapEntity* idMapEntity::ParseJSON( idLexer& src )
|
|
|
|
{
|
|
|
|
idToken token;
|
|
|
|
idMapEntity* mapEnt;
|
|
|
|
//idMapPatch* mapPatch;
|
|
|
|
//idMapBrush* mapBrush;
|
|
|
|
// RB begin
|
|
|
|
MapPolygonMesh* mapMesh;
|
|
|
|
// RB end
|
|
|
|
bool worldent;
|
|
|
|
idVec3 origin;
|
|
|
|
double v1, v2, v3;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "]" )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "," )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token != "{" )
|
|
|
|
{
|
|
|
|
src.Error( "idMapEntity::ParseJSON: { not found, found %s", token.c_str() );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
mapEnt = new idMapEntity();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
/*
|
|
|
|
if( worldSpawn )
|
|
|
|
{
|
|
|
|
mapEnt->primitives.Resize( 1024, 256 );
|
|
|
|
}
|
|
|
|
*/
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
origin.Zero();
|
|
|
|
worldent = false;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "idMapEntity::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "}" )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "," )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// RB: new mesh primitive with ngons
|
|
|
|
if( token == "primitives" )
|
|
|
|
{
|
|
|
|
if( !src.ExpectTokenString( ":" ) )
|
|
|
|
{
|
|
|
|
delete mapEnt;
|
|
|
|
src.Error( "idMapEntity::ParseJSON: expected : for primitives" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.ExpectTokenString( "[" ) )
|
|
|
|
{
|
|
|
|
delete mapEnt;
|
|
|
|
src.Error( "idMapEntity::ParseJSON: expected [ for primitives" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "idMapEntity::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "]" )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "," )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "{" )
|
|
|
|
{
|
|
|
|
mapMesh = MapPolygonMesh::ParseJSON( src );
|
|
|
|
if( !mapMesh )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
mapEnt->AddPrimitive( mapMesh );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
idStr key, value;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// parse a key / value pair
|
|
|
|
key = token;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "idMapEntity::ParseJSON: EOF without closing brace" );
|
|
|
|
delete mapEnt;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token != ":" )
|
|
|
|
{
|
|
|
|
delete mapEnt;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
src.ReadTokenOnLine( &token );
|
|
|
|
value = token;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// strip trailing spaces that sometimes get accidentally
|
|
|
|
// added in the editor
|
|
|
|
value.StripTrailingWhitespace();
|
|
|
|
key.StripTrailingWhitespace();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
mapEnt->epairs.Set( key, value );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !idStr::Icmp( key, "origin" ) )
|
|
|
|
{
|
|
|
|
// 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" ) )
|
|
|
|
{
|
|
|
|
worldent = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while( 1 );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
return mapEnt;
|
|
|
|
}
|
|
|
|
// RB end
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapEntity::RemovePrimitiveData
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idMapEntity::RemovePrimitiveData()
|
|
|
|
{
|
|
|
|
primitives.DeleteContents( true );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapEntity::GetGeometryCRC
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
unsigned int idMapEntity::GetGeometryCRC() const
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i;
|
|
|
|
unsigned int crc;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapPrimitive* mapPrim;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
crc = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
for( i = 0; i < GetNumPrimitives(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
mapPrim = GetPrimitive( i );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
switch( mapPrim->GetType() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
case idMapPrimitive::TYPE_BRUSH:
|
2012-11-28 15:47:07 +00:00
|
|
|
crc ^= static_cast<idMapBrush*>( mapPrim )->GetGeometryCRC();
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
case idMapPrimitive::TYPE_PATCH:
|
2012-11-28 15:47:07 +00:00
|
|
|
crc ^= static_cast<idMapPatch*>( mapPrim )->GetGeometryCRC();
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// RB begin
|
|
|
|
case idMapPrimitive::TYPE_MESH:
|
|
|
|
crc ^= static_cast<MapPolygonMesh*>( mapPrim )->GetGeometryCRC();
|
|
|
|
break;
|
|
|
|
// RB end
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
2021-09-04 18:36:27 +00:00
|
|
|
/*
|
|
|
|
===============
|
2022-01-07 17:46:35 +00:00
|
|
|
Admer
|
|
|
|
|
2021-09-04 18:36:27 +00:00
|
|
|
idMapEntity::CalculateBrushOrigin
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void idMapEntity::CalculateBrushOrigin()
|
|
|
|
{
|
|
|
|
// Collect the origin brushes
|
|
|
|
idList<idMapBrush*> originBrushes;
|
2021-09-11 16:02:16 +00:00
|
|
|
for( int i = 0; i < primitives.Num(); i++ )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
2021-09-11 16:02:16 +00:00
|
|
|
if( primitives[i]->GetType() == idMapPrimitive::TYPE_BRUSH )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
|
|
|
idMapBrush* brush = static_cast<idMapBrush*>( primitives[i] );
|
2021-09-11 16:02:16 +00:00
|
|
|
if( brush->IsOriginBrush() )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
|
|
|
originBrushes.Append( brush );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-11 16:02:16 +00:00
|
|
|
if( !originBrushes.Num() )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accumulate and average the origin brushes centres
|
2021-09-11 16:02:16 +00:00
|
|
|
for( int i = 0; i < originBrushes.Num(); i++ )
|
2021-09-04 18:36:27 +00:00
|
|
|
{
|
|
|
|
MapPolygonMesh mesh;
|
|
|
|
idBounds bounds;
|
|
|
|
|
|
|
|
mesh.ConvertFromBrush( originBrushes[i], 0, 0 );
|
|
|
|
mesh.GetBounds( bounds );
|
|
|
|
|
|
|
|
originOffset += bounds.GetCenter();
|
|
|
|
}
|
|
|
|
|
|
|
|
originOffset /= static_cast<float>( originBrushes.Num() );
|
|
|
|
}
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
class idSort_CompareMapEntity : public idSort_Quick< idMapEntity*, idSort_CompareMapEntity >
|
|
|
|
{
|
|
|
|
public:
|
2016-06-19 15:19:24 +00:00
|
|
|
int Compare( idMapEntity* const& a, idMapEntity* const& b ) const
|
2016-03-05 19:52:09 +00:00
|
|
|
{
|
|
|
|
if( idStr::Icmp( a->epairs.GetString( "name" ), "worldspawn" ) == 0 )
|
|
|
|
{
|
2016-06-19 15:19:24 +00:00
|
|
|
return 1;
|
2016-03-05 19:52:09 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( idStr::Icmp( b->epairs.GetString( "name" ), "worldspawn" ) == 0 )
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
return idStr::Icmp( a->epairs.GetString( "name" ), b->epairs.GetString( "name" ) );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::Parse
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
2012-11-28 15:47:07 +00:00
|
|
|
idMapEntity* mapEnt;
|
2012-11-26 18:58:24 +00:00
|
|
|
int i, j, k;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
name = filename;
|
|
|
|
name.StripFileExtension();
|
2021-10-10 15:47:24 +00:00
|
|
|
name.StripFileExtension(); // RB: there might be .map.map
|
2012-11-26 18:58:24 +00:00
|
|
|
fullName = name;
|
|
|
|
hasPrimitiveData = false;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
bool isJSON = false;
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !ignoreRegion )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
// RB: try loading a .json file first
|
|
|
|
fullName.SetFileExtension( "json" );
|
2012-11-26 18:58:24 +00:00
|
|
|
src.LoadFile( fullName, osPath );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( src.IsLoaded() )
|
|
|
|
{
|
|
|
|
isJSON = true;
|
|
|
|
}
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.IsLoaded() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// now try a .map file
|
|
|
|
fullName.SetFileExtension( "map" );
|
|
|
|
src.LoadFile( fullName, osPath );
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !src.IsLoaded() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// didn't get anything at all
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
version = OLD_MAP_VERSION;
|
|
|
|
fileTime = src.GetFileTime();
|
|
|
|
entities.DeleteContents( true );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
2012-11-28 15:47:07 +00:00
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
return false;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2021-02-13 17:46:34 +00:00
|
|
|
// RB: TODO check for JSON in another way
|
|
|
|
//if( token == "{" )
|
|
|
|
//{
|
|
|
|
// isJSON = true;
|
|
|
|
//}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( isJSON )
|
|
|
|
{
|
|
|
|
while( true )
|
2012-11-28 15:47:07 +00:00
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "entities" )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token != ":" )
|
|
|
|
{
|
|
|
|
src.Error( "idMapFile::Parse: : not found, found %s", token.c_str() );
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token != "[" )
|
|
|
|
{
|
|
|
|
src.Error( "idMapFile::Parse: [ not found, found %s", token.c_str() );
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
mapEnt = idMapEntity::ParseJSON( src );
|
|
|
|
if( !mapEnt )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
entities.Append( mapEnt );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-06-19 15:19:24 +00:00
|
|
|
//entities.SortWithTemplate( idSort_CompareMapEntity() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-06-19 15:19:24 +00:00
|
|
|
if( entities.Num() > 0 && ( idStr::Icmp( entities[0]->epairs.GetString( "name" ), "worldspawn" ) != 0 ) )
|
|
|
|
{
|
|
|
|
// move world spawn to first place
|
|
|
|
for( int i = 1; i < entities.Num(); i++ )
|
|
|
|
{
|
|
|
|
if( idStr::Icmp( entities[i]->epairs.GetString( "name" ), "worldspawn" ) == 0 )
|
|
|
|
{
|
|
|
|
idMapEntity* tmp = entities[0];
|
|
|
|
entities[0] = entities[i];
|
|
|
|
entities[i] = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-05 19:52:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( token == "Version" )
|
|
|
|
{
|
|
|
|
src.ReadTokenOnLine( &token );
|
|
|
|
version = token.GetFloatValue();
|
|
|
|
}
|
2021-02-13 17:46:34 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Valve 220 format and idMapEntity::Parse will expect {
|
|
|
|
src.UnreadToken( &token );
|
2021-03-12 17:13:33 +00:00
|
|
|
valve220Format = true;
|
2021-02-13 17:46:34 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
mapEnt = idMapEntity::Parse( src, ( entities.Num() == 0 ), version );
|
|
|
|
if( !mapEnt )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
entities.Append( mapEnt );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
SetGeometryCRC();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// if the map has a worldspawn
|
2012-11-28 15:47:07 +00:00
|
|
|
if( entities.Num() )
|
|
|
|
{
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// "removeEntities" "classname" can be set in the worldspawn to remove all entities with the given classname
|
2012-11-28 15:47:07 +00:00
|
|
|
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 );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// "overrideMaterial" "material" can be set in the worldspawn to reset all materials
|
|
|
|
idStr material;
|
2012-11-28 15:47:07 +00:00
|
|
|
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];
|
2012-11-28 15:47:07 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
case idMapPrimitive::TYPE_PATCH:
|
|
|
|
{
|
|
|
|
static_cast<idMapPatch*>( mapPrimitive )->SetMaterial( material );
|
2012-11-26 18:58:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// force all entities to have a name key/value pair
|
2012-11-28 15:47:07 +00:00
|
|
|
if( entities[0]->epairs.GetBool( "forceEntityNames" ) )
|
|
|
|
{
|
|
|
|
for( i = 1; i < entities.Num(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
mapEnt = entities[i];
|
2012-11-28 15:47:07 +00:00
|
|
|
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 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// move the primitives of any func_group entities to the worldspawn
|
2012-11-28 15:47:07 +00:00
|
|
|
if( entities[0]->epairs.GetBool( "moveFuncGroups" ) )
|
|
|
|
{
|
|
|
|
for( i = 1; i < entities.Num(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
mapEnt = entities[i];
|
2012-11-28 15:47:07 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2021-10-10 15:47:24 +00:00
|
|
|
// RB: <name>_extraents.map allows to add and override existing entities
|
|
|
|
idMapFile extrasMap;
|
|
|
|
fullName = name;
|
|
|
|
//fullName.StripFileExtension();
|
|
|
|
fullName += "_extra_ents.map";
|
|
|
|
|
|
|
|
if( extrasMap.Parse( fullName, ignoreRegion, osPath ) )
|
|
|
|
{
|
|
|
|
for( i = 0; i < extrasMap.entities.Num(); i++ )
|
|
|
|
{
|
|
|
|
idMapEntity* extraEnt = extrasMap.entities[i];
|
|
|
|
|
|
|
|
const idKeyValue* kv = extraEnt->epairs.FindKey( "name" );
|
|
|
|
if( kv && kv->GetValue().Length() )
|
|
|
|
{
|
|
|
|
mapEnt = FindEntity( kv->GetValue().c_str() );
|
|
|
|
if( mapEnt )
|
|
|
|
{
|
2021-10-20 12:49:45 +00:00
|
|
|
// allow override old settings
|
|
|
|
for( int j = 0; j < extraEnt->epairs.GetNumKeyVals(); j++ )
|
|
|
|
{
|
|
|
|
const idKeyValue* pair = extraEnt->epairs.GetKeyVal( j );
|
|
|
|
if( pair && pair->GetValue().Length() )
|
|
|
|
{
|
|
|
|
mapEnt->epairs.Set( pair->GetKey(), pair->GetValue() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-10 15:47:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
mapEnt = new( TAG_SYSTEM ) idMapEntity();
|
|
|
|
entities.Append( mapEnt );
|
|
|
|
|
|
|
|
// don't grab brushes or polys
|
|
|
|
mapEnt->epairs.Copy( extraEnt->epairs );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
fullName = name;
|
|
|
|
fullName += "_extra_debug.map";
|
|
|
|
|
|
|
|
Write( fullName, ".map" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
hasPrimitiveData = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
idMapFile::Write
|
|
|
|
============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idMapFile::Write( const char* fileName, const char* ext, bool fromBasePath )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i;
|
|
|
|
idStr qpath;
|
2012-11-28 15:47:07 +00:00
|
|
|
idFile* fp;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
qpath = fileName;
|
|
|
|
qpath.SetFileExtension( ext );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
idLib::common->Printf( "writing %s...\n", qpath.c_str() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( fromBasePath )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
fp = idLib::fileSystem->OpenFileWrite( qpath, "fs_basepath" );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
fp = idLib::fileSystem->OpenExplicitFileWrite( qpath );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !fp )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
idLib::common->Warning( "Couldn't open %s\n", qpath.c_str() );
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2021-03-12 17:13:33 +00:00
|
|
|
if( valve220Format )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "// Game: Doom 3 BFG\n// Format: Doom3 (Valve)\n" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "Version %f\n", ( float ) CURRENT_MAP_VERSION );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
for( i = 0; i < entities.Num(); i++ )
|
|
|
|
{
|
2021-03-12 17:13:33 +00:00
|
|
|
entities[i]->Write( fp, i, valve220Format );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
idLib::fileSystem->CloseFile( fp );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// RB begin
|
|
|
|
bool idMapFile::WriteJSON( const char* fileName, const char* ext, bool fromBasePath )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
idStr qpath;
|
|
|
|
idFile* fp;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
qpath = fileName;
|
|
|
|
qpath.SetFileExtension( ext );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
idLib::common->Printf( "writing %s...\n", qpath.c_str() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( fromBasePath )
|
|
|
|
{
|
|
|
|
fp = idLib::fileSystem->OpenFileWrite( qpath, "fs_basepath" );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp = idLib::fileSystem->OpenExplicitFileWrite( qpath );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !fp )
|
|
|
|
{
|
|
|
|
idLib::common->Warning( "Couldn't open %s\n", qpath.c_str() );
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->Printf( "{\n" );
|
|
|
|
fp->WriteFloatString( "\t\"version\": \"%f\",\n", ( float ) CURRENT_MAP_VERSION );
|
|
|
|
fp->Printf( "\t\"entities\": \n\t[\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
for( i = 0; i < entities.Num(); i++ )
|
|
|
|
{
|
|
|
|
entities[i]->WriteJSON( fp, i, entities.Num() );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->Printf( "\t]\n" );
|
|
|
|
fp->Printf( "}\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
idLib::fileSystem->CloseFile( fp );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// RB end
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::SetGeometryCRC
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idMapFile::SetGeometryCRC()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int i;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
geometryCRC = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
for( i = 0; i < entities.Num(); i++ )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
geometryCRC ^= entities[i]->GetGeometryCRC();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::AddEntity
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
int idMapFile::AddEntity( idMapEntity* mapEnt )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int ret = entities.Append( mapEnt );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::FindEntity
|
|
|
|
===============
|
|
|
|
*/
|
2022-02-05 14:49:50 +00:00
|
|
|
idMapEntity* idMapFile::FindEntity( const char* name ) const
|
2012-11-28 15:47:07 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-02-20 18:07:08 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
RB idMapFile::FindEntityAtOrigin
|
|
|
|
===============
|
|
|
|
*/
|
2022-02-05 14:49:50 +00:00
|
|
|
idMapEntity* idMapFile::FindEntityAtOrigin( const idVec3& org ) const
|
2021-02-20 18:07:08 +00:00
|
|
|
{
|
|
|
|
idBounds bo( org );
|
|
|
|
bo.ExpandSelf( 0.125f );
|
|
|
|
|
|
|
|
for( int i = 0; i < entities.Num(); i++ )
|
|
|
|
{
|
|
|
|
idMapEntity* ent = entities[i];
|
|
|
|
|
|
|
|
idVec3 entPos;
|
|
|
|
ent->epairs.GetVector( "origin", "", entPos );
|
|
|
|
|
|
|
|
if( bo.ContainsPoint( entPos ) )
|
|
|
|
{
|
|
|
|
return ent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-02-05 14:49:50 +00:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
RB from idGameEdit::GetUniqueEntityName
|
|
|
|
|
|
|
|
generates a unique name for a given classname
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
const char* idMapFile::GetUniqueEntityName( const char* classname ) const
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
static char name[1024];
|
|
|
|
|
|
|
|
// can only have MAX_GENTITIES, so if we have a spot available, we're guaranteed to find one
|
|
|
|
for( id = 0; id < 99999; id++ )
|
|
|
|
{
|
|
|
|
idStr::snPrintf( name, sizeof( name ), "%s_%d", classname, id );
|
|
|
|
if( FindEntity( name ) == NULL )
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// id == MAX_GENTITIES + 1, which can't be in use if we get here
|
|
|
|
idStr::snPrintf( name, sizeof( name ), "%s_%d", classname, id );
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::RemoveEntity
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idMapFile::RemoveEntity( idMapEntity* mapEnt )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
entities.Remove( mapEnt );
|
|
|
|
delete mapEnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::RemoveEntity
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void idMapFile::RemoveAllEntities()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
entities.DeleteContents( true );
|
|
|
|
hasPrimitiveData = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
idMapFile::RemovePrimitiveData
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
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
|
|
|
|
===============
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
bool idMapFile::NeedsReload()
|
|
|
|
{
|
|
|
|
if( name.Length() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
ID_TIME_T time = FILE_NOT_FOUND_TIMESTAMP;
|
2012-11-28 15:47:07 +00:00
|
|
|
if( idLib::fileSystem->ReadFile( name, NULL, &time ) > 0 )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return ( time > fileTime );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-12 09:53:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
// RB begin
|
|
|
|
MapPolygonMesh::MapPolygonMesh()
|
|
|
|
{
|
|
|
|
type = TYPE_MESH;
|
2016-03-05 19:52:09 +00:00
|
|
|
originalType = TYPE_MESH;
|
2015-04-12 09:53:05 +00:00
|
|
|
polygons.Resize( 8, 4 );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
contents = CONTENTS_SOLID;
|
|
|
|
opaque = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapPolygonMesh::ConvertFromBrush( const idMapBrush* mapBrush, int entityNum, int primitiveNum )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
originalType = TYPE_BRUSH;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// 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 );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
idList<idFixedWinding> planeWindings;
|
|
|
|
idBounds bounds;
|
|
|
|
bounds.Clear();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
int numVerts = 0;
|
|
|
|
int numIndexes = 0;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
bool badBrush = false;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( int i = 0; i < mapBrush->GetNumSides(); i++ )
|
|
|
|
{
|
|
|
|
idMapBrushSide* mapSide = mapBrush->GetSide( i );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
const idMaterial* material = declManager->FindMaterial( mapSide->GetMaterial() );
|
|
|
|
//contents |= ( material->GetContentFlags() & CONTENTS_REMOVE_UTIL );
|
|
|
|
//materials.AddUnique( material );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// chop base plane by other brush sides
|
|
|
|
idFixedWinding& w = planeWindings.Alloc();
|
|
|
|
w.BaseForPlane( -planes[i] );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !w.GetNumPoints() )
|
|
|
|
{
|
|
|
|
common->Printf( "Entity %i, Brush %i: base winding has no points\n", entityNum, primitiveNum );
|
|
|
|
badBrush = true;
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( int j = 0; j < mapBrush->GetNumSides() && w.GetNumPoints(); j++ )
|
|
|
|
{
|
|
|
|
if( i == j )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( w.GetNumPoints() <= 2 )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// only used for debugging
|
|
|
|
for( int j = 0; j < w.GetNumPoints(); j++ )
|
|
|
|
{
|
|
|
|
const idVec3& v = w[j].ToVec3();
|
|
|
|
bounds.AddPoint( v );
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( badBrush )
|
|
|
|
{
|
|
|
|
//common->Error( "" )
|
|
|
|
return;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// copy the data from the windings and build polygons
|
|
|
|
for( int i = 0; i < mapBrush->GetNumSides(); i++ )
|
|
|
|
{
|
|
|
|
idMapBrushSide* mapSide = mapBrush->GetSide( i );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
idFixedWinding& w = planeWindings[i];
|
|
|
|
if( !w.GetNumPoints() )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
MapPolygon& polygon = polygons.Alloc();
|
|
|
|
polygon.SetMaterial( mapSide->GetMaterial() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//for( int j = 0; j < w.GetNumPoints(); j++ )
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// reverse order, so normal does not point inwards
|
|
|
|
for( int j = w.GetNumPoints() - 1; j >= 0; j-- )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
polygon.AddIndex( verts.Num() + j );
|
2015-04-12 09:53:05 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( int j = 0; j < w.GetNumPoints(); j++ )
|
|
|
|
{
|
|
|
|
idDrawVert& dv = verts.Alloc();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
const idVec3& xyz = w[j].ToVec3();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
dv.xyz = xyz;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// calculate texture s/t from brush primitive texture matrix
|
|
|
|
idVec4 texVec[2];
|
|
|
|
mapSide->GetTextureVectors( texVec );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
idVec2 st;
|
|
|
|
st.x = ( xyz * texVec[0].ToVec3() ) + texVec[0][3];
|
|
|
|
st.y = ( xyz * texVec[1].ToVec3() ) + texVec[1][3];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// flip y
|
|
|
|
//st.y = 1.0f - st.y;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
dv.SetTexCoord( st );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// copy normal
|
|
|
|
dv.SetNormal( mapSide->GetPlane().Normal() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//if( dv->GetNormal().Length() < 0.9 || dv->GetNormal().Length() > 1.1 )
|
|
|
|
//{
|
|
|
|
// common->Error( "Bad normal in TriListForSide" );
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
SetContents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapPolygonMesh::ConvertFromPatch( const idMapPatch* patch, int entityNum, int primitiveNum )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
originalType = TYPE_PATCH;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
idSurface_Patch* cp = new idSurface_Patch( *patch );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
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 );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( int i = 0; i < cp->GetNumIndexes(); i += 3 )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
verts.Append( ( *cp )[cp->GetIndexes()[i + 1]] );
|
|
|
|
verts.Append( ( *cp )[cp->GetIndexes()[i + 2]] );
|
|
|
|
verts.Append( ( *cp )[cp->GetIndexes()[i + 0]] );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
for( int i = 0; i < cp->GetNumIndexes(); i += 3 )
|
|
|
|
{
|
|
|
|
MapPolygon& polygon = polygons.Alloc();
|
|
|
|
polygon.SetMaterial( patch->GetMaterial() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
polygon.AddIndex( i + 0 );
|
|
|
|
polygon.AddIndex( i + 1 );
|
|
|
|
polygon.AddIndex( i + 2 );
|
2015-04-12 09:53:05 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
delete cp;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
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() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
fp->WriteFloatString( " ( %d %d 0 0 0 )\n", verts.Num(), polygons.Num() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
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();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//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" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
fp->WriteFloatString( " (\n" );
|
|
|
|
for( int i = 0; i < polygons.Num(); i++ )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
const MapPolygon& poly = polygons[ i ];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( " \"%s\" %d = ", poly.GetMaterial(), poly.indexes.Num() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
for( int j = 0; j < poly.indexes.Num(); j++ )
|
2015-04-12 09:53:05 +00:00
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "%d ", poly.indexes[j] );
|
2015-04-12 09:53:05 +00:00
|
|
|
}
|
|
|
|
fp->WriteFloatString( "\n" );
|
|
|
|
}
|
|
|
|
fp->WriteFloatString( " )\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
fp->WriteFloatString( " }\n}\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
bool MapPolygonMesh::WriteJSON( idFile* fp, int primitiveNum, const idVec3& origin ) const
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "\t\t\t\t{\n\t\t\t\t\t\"primitive\": \"%d\",\n", primitiveNum );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( originalType == TYPE_BRUSH )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "\t\t\t\t\t\"original\": \"brush\",\n" );
|
|
|
|
}
|
|
|
|
else if( originalType == TYPE_PATCH )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "\t\t\t\t\t\"original\": \"curve\",\n" );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t\t\t\t\"verts\":\n\t\t\t\t\t[\n" );
|
|
|
|
idVec2 st;
|
|
|
|
idVec3 n;
|
|
|
|
for( int i = 0; i < verts.Num(); i++ )
|
|
|
|
{
|
|
|
|
const idDrawVert& v = verts[ i ];
|
|
|
|
st = v.GetTexCoord();
|
|
|
|
n = v.GetNormalRaw();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
//if( IsNAN( v.xyz ) )
|
|
|
|
//{
|
|
|
|
// continue;
|
|
|
|
//}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
//idVec3 xyz = v.xyz - origin;
|
|
|
|
fp->WriteFloatString( "\t\t\t\t\t\t{ \"xyz\": [%f, %f, %f], \"st\": [%f, %f], \"normal\": [%f, %f, %f] }%s\n", v.xyz[0], v.xyz[1], v.xyz[2], st[0], st[1], n[0], n[1], n[2], ( i == ( verts.Num() - 1 ) ) ? "" : "," );
|
|
|
|
}
|
|
|
|
fp->WriteFloatString( "\t\t\t\t\t],\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t\t\t\t\"polygons\":\n\t\t\t\t\t[\n" );
|
|
|
|
for( int i = 0; i < polygons.Num(); i++ )
|
|
|
|
{
|
|
|
|
const MapPolygon& poly = polygons[ i ];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t\t\t\t\t{ \"material\": \"%s\", \"indices\": [", poly.GetMaterial() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
#if 0
|
|
|
|
for( int j = 0; j < poly.indexes.Num(); j++ )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "%d%s", poly.indexes[j], ( j == poly.indexes.Num() - 1 ) ? "" : ", " );
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
for( int j = poly.indexes.Num() - 1 ; j >= 0; j-- )
|
|
|
|
{
|
|
|
|
fp->WriteFloatString( "%d%s", poly.indexes[j], ( j == 0 ) ? "" : ", " );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
fp->WriteFloatString( "] }%s\n", ( i == ( polygons.Num() - 1 ) ) ? "" : "," );
|
|
|
|
}
|
|
|
|
fp->WriteFloatString( "\t\t\t\t\t]\n" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
fp->WriteFloatString( "\t\t\t\t}" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
MapPolygonMesh* MapPolygonMesh::Parse( idLexer& src, const idVec3& origin, float version )
|
|
|
|
{
|
|
|
|
float info[7];
|
|
|
|
idToken token;
|
|
|
|
int i;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.ExpectTokenString( "{" ) )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// Parse it
|
|
|
|
if( !src.Parse1DMatrix( 5, info ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::Parse: unable to parse meshDef info" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
const int numVertices = ( int ) info[0];
|
|
|
|
const int numPolygons = ( int ) info[1];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
MapPolygonMesh* mesh = new MapPolygonMesh();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// parse vertices
|
|
|
|
if( !src.ExpectTokenString( "(" ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::Parse: bad mesh vertex data" );
|
|
|
|
delete mesh;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( i = 0; i < numVertices; i++ )
|
|
|
|
{
|
|
|
|
float v[8];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.Parse1DMatrix( 8, v ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::Parse: bad vertex column data" );
|
|
|
|
delete mesh;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// TODO optimize: preallocate vertices
|
|
|
|
//vert = &( ( *patch )[i * patch->GetWidth() + j] );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
idDrawVert vert;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +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] );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
idVec3 n( v[5], v[6], v[7] );
|
|
|
|
vert.SetNormal( n );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
mesh->AddVertex( vert );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.ExpectTokenString( ")" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::Parse: unable to parse vertices" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// parse polygons
|
|
|
|
if( !src.ExpectTokenString( "(" ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::Parse: bad mesh polygon data" );
|
|
|
|
delete mesh;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( i = 0; i < numPolygons; i++ )
|
|
|
|
{
|
|
|
|
// get material name
|
2016-03-05 19:52:09 +00:00
|
|
|
MapPolygon& polygon = mesh->polygons.Alloc();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
src.ReadToken( &token );
|
|
|
|
if( token.type == TT_STRING )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
polygon.SetMaterial( token );;
|
2015-04-12 09:53:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::Parse: bad mesh polygon data" );
|
|
|
|
delete mesh;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
int numIndexes = src.ParseInt();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.ExpectTokenString( "=" ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::Parse: bad mesh polygon data" );
|
|
|
|
delete mesh;
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//idTempArray<int> indexes( numIndexes );
|
|
|
|
for( int j = 0; j < numIndexes; j++ )
|
|
|
|
{
|
|
|
|
//indexes[j] = src.ParseInt();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
int index = src.ParseInt();
|
2016-03-05 19:52:09 +00:00
|
|
|
polygon.AddIndex( index );
|
2015-04-12 09:53:05 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//polygon->SetIndexes( indexes );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.ExpectTokenString( ")" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::Parse: unable to parse polygons" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.ExpectTokenString( "}" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::Parse: unable to parse mesh primitive end" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( !src.ExpectTokenString( "}" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::Parse: unable to parse mesh primitive end" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
mesh->SetContents();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
MapPolygonMesh* MapPolygonMesh::ParseJSON( idLexer& src )
|
|
|
|
{
|
|
|
|
idToken token;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
MapPolygonMesh* mesh = new MapPolygonMesh();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "}" )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "," )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "verts" )
|
|
|
|
{
|
|
|
|
idDrawVert vert;
|
|
|
|
float v[8];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "}" )
|
|
|
|
{
|
|
|
|
mesh->AddVertex( vert );
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "]" )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "," )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "xyz" )
|
|
|
|
{
|
|
|
|
if( !src.ExpectTokenString( ":" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.Parse1DMatrixJSON( 3, v ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: bad vertex column data" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
vert.xyz[0] = v[0];
|
|
|
|
vert.xyz[1] = v[1];
|
|
|
|
vert.xyz[2] = v[2];
|
|
|
|
}
|
|
|
|
else if( token == "st" )
|
|
|
|
{
|
|
|
|
if( !src.ExpectTokenString( ":" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.Parse1DMatrixJSON( 2, v ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: bad vertex column data" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
vert.SetTexCoord( v[0], v[1] );
|
|
|
|
}
|
|
|
|
else if( token == "normal" )
|
|
|
|
{
|
|
|
|
if( !src.ExpectTokenString( ":" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( !src.Parse1DMatrixJSON( 3, v ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: bad vertex column data" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
idVec3 n( v[0], v[1], v[2] );
|
|
|
|
vert.SetNormal( n );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "polygons" )
|
|
|
|
{
|
|
|
|
MapPolygon* polygon = NULL;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "{" )
|
|
|
|
{
|
|
|
|
polygon = &mesh->polygons.Alloc();
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "]" )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "," )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "material" )
|
|
|
|
{
|
|
|
|
if( !src.ExpectTokenString( ":" ) )
|
|
|
|
{
|
|
|
|
delete mesh;
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
src.ReadToken( &token );
|
|
|
|
if( token.type == TT_STRING )
|
|
|
|
{
|
|
|
|
polygon->SetMaterial( token );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( token == "indices" )
|
|
|
|
{
|
|
|
|
idList<int> indices;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
if( !src.ReadToken( &token ) )
|
|
|
|
{
|
|
|
|
src.Error( "MapPolygonMesh::ParseJSON: EOF without closing brace" );
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
if( token == "]" )
|
|
|
|
{
|
|
|
|
// reverse order from Blender
|
|
|
|
for( int i = indices.Num() - 1; i >= 0; i-- )
|
|
|
|
{
|
|
|
|
polygon->AddIndex( indices[i] );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if( token.type == TT_NUMBER )
|
|
|
|
{
|
|
|
|
int index = token.GetIntValue();
|
|
|
|
indices.Append( index );
|
|
|
|
}
|
|
|
|
else if( token == "," )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
mesh->SetContents();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
void MapPolygonMesh::SetContents()
|
|
|
|
{
|
|
|
|
if( polygons.Num() < 1 )
|
|
|
|
{
|
|
|
|
contents = CONTENTS_SOLID;
|
|
|
|
opaque = true;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
int c2;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
MapPolygon* poly = &polygons[0];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
const idMaterial* mat = declManager->FindMaterial( poly->GetMaterial() );
|
|
|
|
contents = mat->GetContentFlags();
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//b->contentShader = s->material;
|
|
|
|
bool mixed = false;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
// a brush is only opaque if all sides are opaque
|
|
|
|
opaque = true;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( int i = 1 ; i < polygons.Num() ; i++ )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
poly = &polygons[i];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
const idMaterial* mat2 = declManager->FindMaterial( poly->GetMaterial() );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
c2 = mat2->GetContentFlags();
|
|
|
|
if( c2 != contents )
|
|
|
|
{
|
|
|
|
mixed = true;
|
|
|
|
contents |= c2;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
if( mat2->Coverage() != MC_OPAQUE )
|
|
|
|
{
|
|
|
|
opaque = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int MapPolygonMesh::GetGeometryCRC() const
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned int crc;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
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 );
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
for( i = 0; i < polygons.Num(); i++ )
|
|
|
|
{
|
2016-03-05 19:52:09 +00:00
|
|
|
const MapPolygon& poly = polygons[i];
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
crc ^= StringCRC( poly.GetMaterial() );
|
2015-04-12 09:53:05 +00:00
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MapPolygonMesh::IsAreaportal() const
|
|
|
|
{
|
|
|
|
return ( ( contents & CONTENTS_AREAPORTAL ) != 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void MapPolygonMesh::GetBounds( idBounds& bounds ) const
|
|
|
|
{
|
|
|
|
if( !verts.Num() )
|
|
|
|
{
|
|
|
|
bounds.Clear();
|
|
|
|
return;
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
bounds[0] = bounds[1] = verts[0].xyz;
|
|
|
|
for( int i = 1; i < verts.Num(); i++ )
|
|
|
|
{
|
|
|
|
const idVec3& p = verts[i].xyz;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
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" );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
//if( classname == "worldspawn" )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < ent->GetNumPrimitives(); i++ )
|
|
|
|
{
|
|
|
|
idMapPrimitive* mapPrim;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
mapPrim = ent->GetPrimitive( i );
|
|
|
|
if( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH )
|
|
|
|
{
|
|
|
|
MapPolygonMesh* meshPrim = new MapPolygonMesh();
|
|
|
|
meshPrim->epairs.Copy( mapPrim->epairs );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
meshPrim->ConvertFromBrush( static_cast<idMapBrush*>( mapPrim ), j, i );
|
|
|
|
ent->primitives[ i ] = meshPrim;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
delete mapPrim;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH )
|
|
|
|
{
|
|
|
|
MapPolygonMesh* meshPrim = new MapPolygonMesh();
|
|
|
|
meshPrim->epairs.Copy( mapPrim->epairs );
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
meshPrim->ConvertFromPatch( static_cast<idMapPatch*>( mapPrim ), j, i );
|
|
|
|
ent->primitives[ i ] = meshPrim;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
delete mapPrim;
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 19:27:44 +00:00
|
|
|
|
2015-04-12 09:53:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
bool idMapFile::ConvertToValve220Format()
|
|
|
|
{
|
|
|
|
valve220Format = true;
|
|
|
|
|
|
|
|
idDict classTypeOverview;
|
2022-01-21 17:33:42 +00:00
|
|
|
idStrList textureCollections;
|
2021-11-09 18:47:06 +00:00
|
|
|
|
|
|
|
int count = GetNumEntities();
|
|
|
|
for( int j = 0; j < count; j++ )
|
|
|
|
{
|
|
|
|
idMapEntity* ent = GetEntity( j );
|
|
|
|
if( ent )
|
|
|
|
{
|
|
|
|
idStr classname = ent->epairs.GetString( "classname" );
|
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
// build entity transform
|
|
|
|
idVec3 origin;
|
|
|
|
origin.Zero();
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
idMat3 rot;
|
|
|
|
rot.Identity();
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
idStr name = ent->epairs.GetString( "name" );
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
origin = ent->epairs.GetVector( "origin", "0 0 0" );
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
if( !ent->epairs.GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", rot ) )
|
|
|
|
{
|
|
|
|
idAngles angles;
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
if( ent->epairs.GetAngles( "angles", "0 0 0", angles ) )
|
|
|
|
{
|
|
|
|
if( angles.pitch != 0.0f || angles.yaw != 0.0f || angles.roll != 0.0f )
|
2021-11-09 18:47:06 +00:00
|
|
|
{
|
2022-01-08 13:30:19 +00:00
|
|
|
rot = angles.ToMat3();
|
2021-11-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-08 13:30:19 +00:00
|
|
|
rot.Identity();
|
2021-11-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-08 13:30:19 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
float angle = ent->epairs.GetFloat( "angle" );
|
|
|
|
if( angle != 0.0f )
|
|
|
|
{
|
|
|
|
rot = idAngles( 0.0f, angle, 0.0f ).ToMat3();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rot.Identity();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
idMat4 transform( rot, origin );
|
|
|
|
//transform.Identity();
|
2021-11-09 18:47:06 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
const idKeyValue* modelPair = ent->epairs.FindKey( "model" );
|
|
|
|
idStr model = ent->epairs.GetString( "model" );
|
|
|
|
#if 1
|
|
|
|
// HACK: convert every old .lwo, .ase model to .obj
|
|
|
|
idStr ext;
|
|
|
|
model.ExtractFileExtension( ext );
|
|
|
|
|
|
|
|
if( ext.Icmp( "lwo" ) == 0 || ext.Icmp( "ase" ) == 0 || ext.Icmp( "dae" ) == 0 )
|
|
|
|
{
|
|
|
|
model.SetFileExtension( "obj" );
|
|
|
|
model = "_tb/" + model;
|
|
|
|
|
|
|
|
ent->epairs.Set( "model", model );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// is this oldschool brushes & patches?
|
|
|
|
if( ent->GetNumPrimitives() > 0 )
|
|
|
|
{
|
2021-11-09 18:47:06 +00:00
|
|
|
#if 1
|
|
|
|
if( !transform.IsIdentity() &&
|
|
|
|
idStr::Icmp( classname, "func_static" ) != 0 &&
|
|
|
|
idStr::Icmp( classname, "light" ) != 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Delete( "origin" );
|
|
|
|
ent->epairs.Delete( "rotation" );
|
|
|
|
ent->epairs.Delete( "angles" );
|
|
|
|
ent->epairs.Delete( "angle" );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-11-09 20:30:49 +00:00
|
|
|
if( idStr::Icmp( classname, "func_static" ) == 0 && idStr::Icmp( model.c_str(), classname.c_str() ) == 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Delete( "model" );
|
|
|
|
}
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
// convert brushes
|
|
|
|
for( int i = 0; i < ent->GetNumPrimitives(); i++ )
|
|
|
|
{
|
|
|
|
idMapPrimitive* mapPrim;
|
|
|
|
|
|
|
|
mapPrim = ent->GetPrimitive( i );
|
|
|
|
if( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH )
|
|
|
|
{
|
|
|
|
idMapBrush* brushPrim = static_cast<idMapBrush*>( mapPrim );
|
|
|
|
for( int s = 0; s < brushPrim->GetNumSides(); s++ )
|
|
|
|
{
|
|
|
|
idMapBrushSide* side = brushPrim->GetSide( s );
|
2022-01-21 17:33:42 +00:00
|
|
|
side->ConvertToValve220Format( transform, textureCollections );
|
2021-11-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-21 17:33:42 +00:00
|
|
|
else if( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH )
|
|
|
|
{
|
|
|
|
idMapPatch* patch = static_cast<idMapPatch*>( mapPrim );
|
|
|
|
idMapFile::AddMaterialToCollection( patch->GetMaterial(), textureCollections );
|
|
|
|
}
|
2021-11-09 18:47:06 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 20:30:49 +00:00
|
|
|
// collect some statistics
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
const idKeyValue* kv = classTypeOverview.FindKey( classname );
|
|
|
|
if( kv && kv->GetValue().Length() )
|
|
|
|
{
|
|
|
|
if( idStr::Icmp( kv->GetValue().c_str(), "PointClass" ) == 0 && idStr::Icmp( kv->GetValue().c_str(), "Mixed" ) != 0 )
|
|
|
|
{
|
|
|
|
classTypeOverview.Set( classname, "Mixed" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
classTypeOverview.Set( classname, "BrushClass" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-01-08 13:30:19 +00:00
|
|
|
// just a regular entity
|
|
|
|
|
2022-01-29 17:10:54 +00:00
|
|
|
// TrenchBroom doesn't allow models for SolidClasses so use helper classes instead
|
2022-01-09 10:41:01 +00:00
|
|
|
if( idStr::Icmp( classname, "func_static" ) == 0 && idStr::Icmp( model.c_str(), classname.c_str() ) != 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "classname", "misc_model" );
|
|
|
|
}
|
2022-01-29 17:10:54 +00:00
|
|
|
else if( idStr::Icmp( classname, "func_door" ) == 0 && idStr::Icmp( model.c_str(), classname.c_str() ) != 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "classname", "func_door_model" );
|
|
|
|
}
|
|
|
|
else if( idStr::Icmp( classname, "func_mover" ) == 0 && idStr::Icmp( model.c_str(), classname.c_str() ) != 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "classname", "func_mover_amodel" );
|
|
|
|
}
|
|
|
|
else if( idStr::Icmp( classname, "func_rotating" ) == 0 && idStr::Icmp( model.c_str(), classname.c_str() ) != 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "classname", "func_rotating_model" );
|
|
|
|
}
|
|
|
|
else if( idStr::Icmp( classname, "func_plat" ) == 0 && idStr::Icmp( model.c_str(), classname.c_str() ) != 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "classname", "func_plat_model" );
|
|
|
|
}
|
2022-01-09 10:41:01 +00:00
|
|
|
|
2022-01-08 13:30:19 +00:00
|
|
|
// replace "rotation" with angles because it is not supported by TrenchBroom
|
|
|
|
if( ent->epairs.FindKey( "rotation" ) )
|
|
|
|
{
|
|
|
|
ent->epairs.Delete( "rotation" );
|
|
|
|
|
|
|
|
idAngles angles = rot.ToAngles();
|
|
|
|
ent->epairs.SetAngles( "angles", angles );
|
|
|
|
}
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
const idKeyValue* kv = classTypeOverview.FindKey( classname );
|
|
|
|
if( kv && kv->GetValue().Length() )
|
|
|
|
{
|
|
|
|
if( idStr::Icmp( kv->GetValue().c_str(), "BrushClass" ) == 0 && idStr::Icmp( kv->GetValue().c_str(), "Mixed" ) != 0 )
|
|
|
|
{
|
|
|
|
classTypeOverview.Set( classname, "Mixed" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
classTypeOverview.Set( classname, "PointClass" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-21 17:33:42 +00:00
|
|
|
idMapEntity* worldspawn = GetEntity( 0 );
|
|
|
|
if( worldspawn )
|
|
|
|
{
|
|
|
|
//worldspawn->epairs.Set( "_tb_textures", "textures/common;textures/editor;textures/decals;textures/decals2" );
|
|
|
|
|
|
|
|
idStr list;
|
|
|
|
for( int i = 0; i < textureCollections.Num(); i++ )
|
|
|
|
{
|
|
|
|
list += textureCollections[ i ];
|
|
|
|
|
|
|
|
if( i != ( textureCollections.Num() - 1 ) )
|
|
|
|
{
|
|
|
|
list += ";";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
worldspawn->epairs.Set( "_tb_textures", list );
|
2022-01-29 17:10:54 +00:00
|
|
|
worldspawn->epairs.Set( "_tb_def", "builtin:DOOM-3-all.fgd" );
|
2022-01-21 17:33:42 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 18:47:06 +00:00
|
|
|
int n = classTypeOverview.GetNumKeyVals();
|
|
|
|
|
|
|
|
idLib::Printf( "BrushClasses:\n" );
|
|
|
|
for( int i = 0; i < n; i++ )
|
|
|
|
{
|
|
|
|
const idKeyValue* kv = classTypeOverview.GetKeyVal( i );
|
|
|
|
|
|
|
|
if( kv->GetValue() == "BrushClass" )
|
|
|
|
{
|
|
|
|
idLib::Printf( "'%s'\n", kv->GetKey().c_str() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
idLib::Printf( "\nPointClasses:\n" );
|
|
|
|
for( int i = 0; i < n; i++ )
|
|
|
|
{
|
|
|
|
const idKeyValue* kv = classTypeOverview.GetKeyVal( i );
|
|
|
|
|
|
|
|
if( kv->GetValue() == "PointClass" )
|
|
|
|
{
|
|
|
|
idLib::Printf( "'%s'\n", kv->GetKey().c_str() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
idLib::Printf( "\nMixedClasses:\n" );
|
|
|
|
for( int i = 0; i < n; i++ )
|
|
|
|
{
|
|
|
|
const idKeyValue* kv = classTypeOverview.GetKeyVal( i );
|
|
|
|
|
|
|
|
if( kv->GetValue() == "Mixed" )
|
|
|
|
{
|
|
|
|
idLib::Printf( "'%s'\n", kv->GetKey().c_str() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-05 14:49:50 +00:00
|
|
|
bool idMapFile::ConvertQuakeToDoom()
|
|
|
|
{
|
|
|
|
idDict classTypeOverview;
|
|
|
|
idStrList textureCollections;
|
|
|
|
|
|
|
|
int count = GetNumEntities();
|
|
|
|
for( int j = 0; j < count; j++ )
|
|
|
|
{
|
|
|
|
idMapEntity* ent = GetEntity( j );
|
|
|
|
if( ent )
|
|
|
|
{
|
|
|
|
idStr classname = ent->epairs.GetString( "classname" );
|
|
|
|
|
|
|
|
const idKeyValue* targetnamePair = ent->epairs.FindKey( "targetname" );
|
|
|
|
if( targetnamePair )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "name", targetnamePair->GetValue() );
|
|
|
|
ent->epairs.Delete( "targetname" );
|
|
|
|
}
|
|
|
|
|
|
|
|
const idKeyValue* namePair = ent->epairs.FindKey( "name" );
|
|
|
|
if( !namePair )
|
|
|
|
{
|
|
|
|
idStr uniqueName = GetUniqueEntityName( classname );
|
|
|
|
|
|
|
|
ent->epairs.Set( "name", uniqueName );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// is there a name clash with another entity?
|
|
|
|
bool clash = false;
|
|
|
|
|
|
|
|
for( int i = 1; i < count; i++ )
|
|
|
|
{
|
|
|
|
if( i == j )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
idMapEntity* otherEnt = GetEntity( i );
|
|
|
|
|
|
|
|
const idKeyValue* otherNamePair = otherEnt->epairs.FindKey( "name" );
|
|
|
|
if( otherNamePair && !otherNamePair->GetValue().IsEmpty() && idStr::Cmp( namePair->GetValue(), otherNamePair->GetValue() ) == 0 )
|
|
|
|
{
|
|
|
|
// both entities have the same name, give this one a new name
|
|
|
|
idStr uniqueName = GetUniqueEntityName( classname );
|
|
|
|
|
|
|
|
ent->epairs.Set( "name", uniqueName );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( idStr::Icmp( classname, "func_wall" ) == 0 )
|
|
|
|
{
|
|
|
|
ent->epairs.Set( "classname", "func_static" );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ent->GetNumPrimitives() > 0 )
|
|
|
|
{
|
|
|
|
const idKeyValue* namePair = ent->epairs.FindKey( "name" );
|
|
|
|
ent->epairs.Set( "model", namePair->GetValue() );
|
|
|
|
|
|
|
|
// map Wad brushes names to proper Doom 3 compatible material names
|
|
|
|
for( int i = 0; i < ent->GetNumPrimitives(); i++ )
|
|
|
|
{
|
|
|
|
idMapPrimitive* mapPrim;
|
|
|
|
|
|
|
|
mapPrim = ent->GetPrimitive( i );
|
|
|
|
if( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH )
|
|
|
|
{
|
|
|
|
idMapBrush* brushPrim = static_cast<idMapBrush*>( mapPrim );
|
|
|
|
for( int s = 0; s < brushPrim->GetNumSides(); s++ )
|
|
|
|
{
|
|
|
|
idMapBrushSide* side = brushPrim->GetSide( s );
|
|
|
|
idStr matName;
|
|
|
|
WadTextureToMaterial( side->GetMaterial(), matName );
|
|
|
|
side->SetMaterial( matName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH )
|
|
|
|
{
|
|
|
|
idMapPatch* patch = static_cast<idMapPatch*>( mapPrim );
|
|
|
|
idMapFile::AddMaterialToCollection( patch->GetMaterial(), textureCollections );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
idMapEntity* worldspawn = GetEntity( 0 );
|
|
|
|
if( worldspawn )
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
worldspawn->epairs.Set( "_tb_textures", "textures/common;textures/editor;textures/id1" );
|
|
|
|
#else
|
|
|
|
TODO
|
|
|
|
|
|
|
|
idStr list;
|
|
|
|
for( int i = 0; i < textureCollections.Num(); i++ )
|
|
|
|
{
|
|
|
|
list += textureCollections[ i ];
|
|
|
|
|
|
|
|
if( i != ( textureCollections.Num() - 1 ) )
|
|
|
|
{
|
|
|
|
list += ";";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
worldspawn->epairs.Set( "_tb_textures", list );
|
|
|
|
#endif
|
|
|
|
worldspawn->epairs.Set( "_tb_def", "builtin:DOOM-3-slim.fgd" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-01-21 17:33:42 +00:00
|
|
|
void idMapFile::AddMaterialToCollection( const char* material, idStrList& textureCollections )
|
|
|
|
{
|
|
|
|
idStr withoutPath = material;
|
|
|
|
withoutPath.StripPath();
|
|
|
|
|
|
|
|
idStr textureCollection = material;
|
|
|
|
textureCollection.StripTrailingOnce( "/" + withoutPath );
|
|
|
|
|
|
|
|
textureCollections.AddUnique( textureCollection );
|
|
|
|
}
|
|
|
|
|
2022-02-05 14:49:50 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
const char* quakeName;
|
|
|
|
const char* doomName;
|
|
|
|
} quakeToDoom_t;
|
|
|
|
|
|
|
|
static quakeToDoom_t textureConvertNames[] =
|
|
|
|
{
|
|
|
|
// id1.wad
|
|
|
|
{"textures/#04awater1", "textures/id1/04awater1"},
|
|
|
|
{"textures/#04mwat1", "textures/id1/04mwat1"},
|
|
|
|
{"textures/#04mwat2", "textures/id1/04mwat2"},
|
|
|
|
{"textures/#04water1", "textures/id1/04water1"},
|
|
|
|
{"textures/#04water2", "textures/id1/04water2"},
|
|
|
|
{"textures/#lava1", "textures/id1/lava1"},
|
|
|
|
{"textures/#slime", "textures/id1/slime"},
|
|
|
|
{"textures/#slime0", "textures/id1/slime0"},
|
|
|
|
{"textures/#slime1", "textures/id1/slime1"},
|
|
|
|
{"textures/#teleport", "textures/id1/teleport"},
|
|
|
|
{"textures/#water0", "textures/id1/water0"},
|
|
|
|
{"textures/#water1", "textures/id1/water1"},
|
|
|
|
{"textures/#water2", "textures/id1/water2"},
|
|
|
|
{"textures/0_box_side", "textures/id1/0_box_side"},
|
|
|
|
{"textures/0_box_top", "textures/id1/0_box_top"},
|
|
|
|
{"textures/0_med100", "textures/id1/0_med100"},
|
|
|
|
{"textures/0_med25", "textures/id1/0_med25"},
|
|
|
|
{"textures/0_med25s", "textures/id1/0_med25s"},
|
|
|
|
{"textures/0basebtn", "textures/id1/0basebtn"},
|
|
|
|
{"textures/0butn", "textures/id1/0butn"},
|
|
|
|
{"textures/0butnn", "textures/id1/0butnn"},
|
|
|
|
{"textures/0button", "textures/id1/0button"},
|
|
|
|
{"textures/0floorsw", "textures/id1/0floorsw"},
|
|
|
|
{"textures/0light01", "textures/id1/0light01"},
|
|
|
|
{"textures/0mtlsw", "textures/id1/0mtlsw"},
|
|
|
|
{"textures/0planet", "textures/id1/0planet"},
|
|
|
|
{"textures/0shoot", "textures/id1/0shoot"},
|
|
|
|
{"textures/0slip", "textures/id1/0slip"},
|
|
|
|
{"textures/0slipbot", "textures/id1/0slipbot"},
|
|
|
|
{"textures/0sliptop", "textures/id1/0sliptop"},
|
|
|
|
{"textures/1_box_side", "textures/id1/1_box_side"},
|
|
|
|
{"textures/1_box_top", "textures/id1/1_box_top"},
|
|
|
|
{"textures/1_med100", "textures/id1/1_med100"},
|
|
|
|
{"textures/1_med25", "textures/id1/1_med25"},
|
|
|
|
{"textures/1_med25s", "textures/id1/1_med25s"},
|
|
|
|
{"textures/1basebtn", "textures/id1/1basebtn"},
|
|
|
|
{"textures/1butn", "textures/id1/1butn"},
|
|
|
|
{"textures/1butnn", "textures/id1/1butnn"},
|
|
|
|
{"textures/1button", "textures/id1/1button"},
|
|
|
|
{"textures/1floorsw", "textures/id1/1floorsw"},
|
|
|
|
{"textures/1light01", "textures/id1/1light01"},
|
|
|
|
{"textures/1mtlsw", "textures/id1/1mtlsw"},
|
|
|
|
{"textures/1planet", "textures/id1/1planet"},
|
|
|
|
{"textures/1shoot", "textures/id1/1shoot"},
|
|
|
|
{"textures/1slip", "textures/id1/1slip"},
|
|
|
|
{"textures/2_med100", "textures/id1/2_med100"},
|
|
|
|
{"textures/2_med25", "textures/id1/2_med25"},
|
|
|
|
{"textures/2butn", "textures/id1/2butn"},
|
|
|
|
{"textures/2butnn", "textures/id1/2butnn"},
|
|
|
|
{"textures/2button", "textures/id1/2button"},
|
|
|
|
{"textures/2floorsw", "textures/id1/2floorsw"},
|
|
|
|
{"textures/2light01", "textures/id1/2light01"},
|
|
|
|
{"textures/2mtlsw", "textures/id1/2mtlsw"},
|
|
|
|
{"textures/2planet", "textures/id1/2planet"},
|
|
|
|
{"textures/2shoot", "textures/id1/2shoot"},
|
|
|
|
{"textures/2slip", "textures/id1/2slip"},
|
|
|
|
{"textures/3_med100", "textures/id1/3_med100"},
|
|
|
|
{"textures/3_med25", "textures/id1/3_med25"},
|
|
|
|
{"textures/3butn", "textures/id1/3butn"},
|
|
|
|
{"textures/3butnn", "textures/id1/3butnn"},
|
|
|
|
{"textures/3button", "textures/id1/3button"},
|
|
|
|
{"textures/3floorsw", "textures/id1/3floorsw"},
|
|
|
|
{"textures/3mtlsw", "textures/id1/3mtlsw"},
|
|
|
|
{"textures/3planet", "textures/id1/3planet"},
|
|
|
|
{"textures/3shoot", "textures/id1/3shoot"},
|
|
|
|
{"textures/3slip", "textures/id1/3slip"},
|
|
|
|
{"textures/4slip", "textures/id1/4slip"},
|
|
|
|
{"textures/5slip", "textures/id1/5slip"},
|
|
|
|
{"textures/6slip", "textures/id1/6slip"},
|
|
|
|
{"textures/abasebtn", "textures/id1/abasebtn"},
|
|
|
|
{"textures/abutn", "textures/id1/abutn"},
|
|
|
|
{"textures/abutnn", "textures/id1/abutnn"},
|
|
|
|
{"textures/abutton", "textures/id1/abutton"},
|
|
|
|
{"textures/afloorsw", "textures/id1/afloorsw"},
|
|
|
|
{"textures/amtlsw", "textures/id1/amtlsw"},
|
|
|
|
{"textures/ashoot", "textures/id1/ashoot"},
|
|
|
|
{"textures/adoor01_2", "textures/id1/adoor01_2"},
|
|
|
|
{"textures/adoor02_2", "textures/id1/adoor02_2"},
|
|
|
|
{"textures/adoor03_2", "textures/id1/adoor03_2"},
|
|
|
|
{"textures/adoor03_3", "textures/id1/adoor03_3"},
|
|
|
|
{"textures/adoor03_4", "textures/id1/adoor03_4"},
|
|
|
|
{"textures/adoor03_5", "textures/id1/adoor03_5"},
|
|
|
|
{"textures/adoor03_6", "textures/id1/adoor03_6"},
|
|
|
|
{"textures/adoor09_1", "textures/id1/adoor09_1"},
|
|
|
|
{"textures/adoor09_2", "textures/id1/adoor09_2"},
|
|
|
|
{"textures/afloor1_3", "textures/id1/afloor1_3"},
|
|
|
|
{"textures/afloor1_4", "textures/id1/afloor1_4"},
|
|
|
|
{"textures/afloor1_8", "textures/id1/afloor1_8"},
|
|
|
|
{"textures/afloor3_1", "textures/id1/afloor3_1"},
|
|
|
|
{"textures/altar1_1", "textures/id1/altar1_1"},
|
|
|
|
{"textures/altar1_3", "textures/id1/altar1_3"},
|
|
|
|
{"textures/altar1_4", "textures/id1/altar1_4"},
|
|
|
|
{"textures/altar1_6", "textures/id1/altar1_6"},
|
|
|
|
{"textures/altar1_7", "textures/id1/altar1_7"},
|
|
|
|
{"textures/altar1_8", "textures/id1/altar1_8"},
|
|
|
|
{"textures/altarb_1", "textures/id1/altarb_1"},
|
|
|
|
{"textures/altarb_2", "textures/id1/altarb_2"},
|
|
|
|
{"textures/altarc_1", "textures/id1/altarc_1"},
|
|
|
|
{"textures/arch7", "textures/id1/arch7"},
|
|
|
|
{"textures/arrow_m", "textures/id1/arrow_m"},
|
|
|
|
{"textures/az1_6", "textures/id1/az1_6"},
|
|
|
|
{"textures/azfloor1_1", "textures/id1/azfloor1_1"},
|
|
|
|
{"textures/azswitch3", "textures/id1/azswitch3"},
|
|
|
|
{"textures/azwall1_5", "textures/id1/azwall1_5"},
|
|
|
|
{"textures/azwall3_1", "textures/id1/azwall3_1"},
|
|
|
|
{"textures/azwall3_2", "textures/id1/azwall3_2"},
|
|
|
|
{"textures/basebutn3", "textures/id1/basebutn3"},
|
|
|
|
{"textures/batt0sid", "textures/id1/batt0sid"},
|
|
|
|
{"textures/batt0top", "textures/id1/batt0top"},
|
|
|
|
{"textures/batt1sid", "textures/id1/batt1sid"},
|
|
|
|
{"textures/batt1top", "textures/id1/batt1top"},
|
|
|
|
{"textures/black", "textures/id1/black"},
|
|
|
|
{"textures/bodiesa2_1", "textures/id1/bodiesa2_1"},
|
|
|
|
{"textures/bodiesa2_4", "textures/id1/bodiesa2_4"},
|
|
|
|
{"textures/bodiesa3_1", "textures/id1/bodiesa3_1"},
|
|
|
|
{"textures/bodiesa3_2", "textures/id1/bodiesa3_2"},
|
|
|
|
{"textures/bodiesa3_3", "textures/id1/bodiesa3_3"},
|
|
|
|
{"textures/bricka2_1", "textures/id1/bricka2_1"},
|
|
|
|
{"textures/bricka2_2", "textures/id1/bricka2_2"},
|
|
|
|
{"textures/bricka2_4", "textures/id1/bricka2_4"},
|
|
|
|
{"textures/bricka2_6", "textures/id1/bricka2_6"},
|
|
|
|
{"textures/carch02", "textures/id1/carch02"},
|
|
|
|
{"textures/carch03", "textures/id1/carch03"},
|
|
|
|
{"textures/carch04_1", "textures/id1/carch04_1"},
|
|
|
|
{"textures/carch04_2", "textures/id1/carch04_2"},
|
|
|
|
{"textures/ceil1_1", "textures/id1/ceil1_1"},
|
|
|
|
{"textures/ceiling1_3", "textures/id1/ceiling1_3"},
|
|
|
|
{"textures/ceiling4", "textures/id1/ceiling4"},
|
|
|
|
{"textures/ceiling5", "textures/id1/ceiling5"},
|
|
|
|
{"textures/church1_2", "textures/id1/church1_2"},
|
|
|
|
{"textures/church7", "textures/id1/church7"},
|
|
|
|
{"textures/city1_4", "textures/id1/city1_4"},
|
|
|
|
{"textures/city1_7", "textures/id1/city1_7"},
|
|
|
|
{"textures/city2_1", "textures/id1/city2_1"},
|
|
|
|
{"textures/city2_2", "textures/id1/city2_2"},
|
|
|
|
{"textures/city2_3", "textures/id1/city2_3"},
|
|
|
|
{"textures/city2_5", "textures/id1/city2_5"},
|
|
|
|
{"textures/city2_6", "textures/id1/city2_6"},
|
|
|
|
{"textures/city2_7", "textures/id1/city2_7"},
|
|
|
|
{"textures/city2_8", "textures/id1/city2_8"},
|
|
|
|
{"textures/city3_2", "textures/id1/city3_2"},
|
|
|
|
{"textures/city3_4", "textures/id1/city3_4"},
|
|
|
|
{"textures/city4_1", "textures/id1/city4_1"},
|
|
|
|
{"textures/city4_2", "textures/id1/city4_2"},
|
|
|
|
{"textures/city4_5", "textures/id1/city4_5"},
|
|
|
|
{"textures/city4_6", "textures/id1/city4_6"},
|
|
|
|
{"textures/city4_7", "textures/id1/city4_7"},
|
|
|
|
{"textures/city4_8", "textures/id1/city4_8"},
|
|
|
|
{"textures/city5_1", "textures/id1/city5_1"},
|
|
|
|
{"textures/city5_2", "textures/id1/city5_2"},
|
|
|
|
{"textures/city5_3", "textures/id1/city5_3"},
|
|
|
|
{"textures/city5_4", "textures/id1/city5_4"},
|
|
|
|
{"textures/city5_6", "textures/id1/city5_6"},
|
|
|
|
{"textures/city5_7", "textures/id1/city5_7"},
|
|
|
|
{"textures/city5_8", "textures/id1/city5_8"},
|
|
|
|
{"textures/city6_3", "textures/id1/city6_3"},
|
|
|
|
{"textures/city6_4", "textures/id1/city6_4"},
|
|
|
|
{"textures/city6_7", "textures/id1/city6_7"},
|
|
|
|
{"textures/city6_8", "textures/id1/city6_8"},
|
|
|
|
{"textures/city8_2", "textures/id1/city8_2"},
|
|
|
|
{"textures/citya1_1", "textures/id1/citya1_1"},
|
|
|
|
{"textures/clip", "textures/common/clip"},
|
|
|
|
{"textures/column01_3", "textures/id1/column01_3"},
|
|
|
|
{"textures/column01_4", "textures/id1/column01_4"},
|
|
|
|
{"textures/column1_2", "textures/id1/column1_2"},
|
|
|
|
{"textures/column1_4", "textures/id1/column1_4"},
|
|
|
|
{"textures/column1_5", "textures/id1/column1_5"},
|
|
|
|
{"textures/comp1_1", "textures/id1/comp1_1"},
|
|
|
|
{"textures/comp1_2", "textures/id1/comp1_2"},
|
|
|
|
{"textures/comp1_3", "textures/id1/comp1_3"},
|
|
|
|
{"textures/comp1_4", "textures/id1/comp1_4"},
|
|
|
|
{"textures/comp1_5", "textures/id1/comp1_5"},
|
|
|
|
{"textures/comp1_6", "textures/id1/comp1_6"},
|
|
|
|
{"textures/comp1_7", "textures/id1/comp1_7"},
|
|
|
|
{"textures/comp1_8", "textures/id1/comp1_8"},
|
|
|
|
{"textures/cop1_1", "textures/id1/cop1_1"},
|
|
|
|
{"textures/cop1_2", "textures/id1/cop1_2"},
|
|
|
|
{"textures/cop1_3", "textures/id1/cop1_3"},
|
|
|
|
{"textures/cop1_4", "textures/id1/cop1_4"},
|
|
|
|
{"textures/cop1_5", "textures/id1/cop1_5"},
|
|
|
|
{"textures/cop1_6", "textures/id1/cop1_6"},
|
|
|
|
{"textures/cop1_7", "textures/id1/cop1_7"},
|
|
|
|
{"textures/cop1_8", "textures/id1/cop1_8"},
|
|
|
|
{"textures/cop2_1", "textures/id1/cop2_1"},
|
|
|
|
{"textures/cop2_2", "textures/id1/cop2_2"},
|
|
|
|
{"textures/cop2_3", "textures/id1/cop2_3"},
|
|
|
|
{"textures/cop2_4", "textures/id1/cop2_4"},
|
|
|
|
{"textures/cop2_5", "textures/id1/cop2_5"},
|
|
|
|
{"textures/cop2_6", "textures/id1/cop2_6"},
|
|
|
|
{"textures/cop3_1", "textures/id1/cop3_1"},
|
|
|
|
{"textures/cop3_2", "textures/id1/cop3_2"},
|
|
|
|
{"textures/cop3_4", "textures/id1/cop3_4"},
|
|
|
|
{"textures/cop4_3", "textures/id1/cop4_3"},
|
|
|
|
{"textures/cop4_5", "textures/id1/cop4_5"},
|
|
|
|
{"textures/crate0_side", "textures/id1/crate0_side"},
|
|
|
|
{"textures/crate0_top", "textures/id1/crate0_top"},
|
|
|
|
{"textures/crate1_side", "textures/id1/crate1_side"},
|
|
|
|
{"textures/crate1_top", "textures/id1/crate1_top"},
|
|
|
|
{"textures/dem4_1", "textures/id1/dem4_1"},
|
|
|
|
{"textures/dem4_4", "textures/id1/dem4_4"},
|
|
|
|
{"textures/dem5_3", "textures/id1/dem5_3"},
|
|
|
|
{"textures/demc4_4", "textures/id1/demc4_4"},
|
|
|
|
{"textures/door01_2", "textures/id1/door01_2"},
|
|
|
|
{"textures/door02_1", "textures/id1/door02_1"},
|
|
|
|
{"textures/door02_2", "textures/id1/door02_2"},
|
|
|
|
{"textures/door02_3", "textures/id1/door02_3"},
|
|
|
|
{"textures/door02_7", "textures/id1/door02_7"},
|
|
|
|
{"textures/door03_2", "textures/id1/door03_2"},
|
|
|
|
{"textures/door03_3", "textures/id1/door03_3"},
|
|
|
|
{"textures/door03_4", "textures/id1/door03_4"},
|
|
|
|
{"textures/door03_5", "textures/id1/door03_5"},
|
|
|
|
{"textures/door04_1", "textures/id1/door04_1"},
|
|
|
|
{"textures/door04_2", "textures/id1/door04_2"},
|
|
|
|
{"textures/door05_2", "textures/id1/door05_2"},
|
|
|
|
{"textures/door05_3", "textures/id1/door05_3"},
|
|
|
|
{"textures/dopeback", "textures/id1/dopeback"},
|
|
|
|
{"textures/dopefish", "textures/id1/dopefish"},
|
|
|
|
{"textures/dr01_1", "textures/id1/dr01_1"},
|
|
|
|
{"textures/dr01_2", "textures/id1/dr01_2"},
|
|
|
|
{"textures/dr02_1", "textures/id1/dr02_1"},
|
|
|
|
{"textures/dr02_2", "textures/id1/dr02_2"},
|
|
|
|
{"textures/dr03_1", "textures/id1/dr03_1"},
|
|
|
|
{"textures/dr05_2", "textures/id1/dr05_2"},
|
|
|
|
{"textures/dr07_1", "textures/id1/dr07_1"},
|
|
|
|
{"textures/dung01_1", "textures/id1/dung01_1"},
|
|
|
|
{"textures/dung01_2", "textures/id1/dung01_2"},
|
|
|
|
{"textures/dung01_3", "textures/id1/dung01_3"},
|
|
|
|
{"textures/dung01_4", "textures/id1/dung01_4"},
|
|
|
|
{"textures/dung01_5", "textures/id1/dung01_5"},
|
|
|
|
{"textures/dung02_1", "textures/id1/dung02_1"},
|
|
|
|
{"textures/dung02_5", "textures/id1/dung02_5"},
|
|
|
|
{"textures/ecop1_1", "textures/id1/ecop1_1"},
|
|
|
|
{"textures/ecop1_4", "textures/id1/ecop1_4"},
|
|
|
|
{"textures/ecop1_6", "textures/id1/ecop1_6"},
|
|
|
|
{"textures/ecop1_7", "textures/id1/ecop1_7"},
|
|
|
|
{"textures/ecop1_8", "textures/id1/ecop1_8"},
|
|
|
|
{"textures/edoor01_1", "textures/id1/edoor01_1"},
|
|
|
|
{"textures/elwall1_1", "textures/id1/elwall1_1"},
|
|
|
|
{"textures/elwall2_4", "textures/id1/elwall2_4"},
|
|
|
|
{"textures/emetal1_3", "textures/id1/emetal1_3"},
|
|
|
|
{"textures/enter01", "textures/id1/enter01"},
|
|
|
|
{"textures/exit01", "textures/id1/exit01"},
|
|
|
|
{"textures/exit02_2", "textures/id1/exit02_2"},
|
|
|
|
{"textures/exit02_3", "textures/id1/exit02_3"},
|
|
|
|
{"textures/floor01_5", "textures/id1/floor01_5"},
|
|
|
|
{"textures/grave01_1", "textures/id1/grave01_1"},
|
|
|
|
{"textures/grave01_3", "textures/id1/grave01_3"},
|
|
|
|
{"textures/grave02_1", "textures/id1/grave02_1"},
|
|
|
|
{"textures/grave02_2", "textures/id1/grave02_2"},
|
|
|
|
{"textures/grave02_3", "textures/id1/grave02_3"},
|
|
|
|
{"textures/grave02_4", "textures/id1/grave02_4"},
|
|
|
|
{"textures/grave02_5", "textures/id1/grave02_5"},
|
|
|
|
{"textures/grave02_6", "textures/id1/grave02_6"},
|
|
|
|
{"textures/grave02_7", "textures/id1/grave02_7"},
|
|
|
|
{"textures/grave03_1", "textures/id1/grave03_1"},
|
|
|
|
{"textures/grave03_2", "textures/id1/grave03_2"},
|
|
|
|
{"textures/grave03_3", "textures/id1/grave03_3"},
|
|
|
|
{"textures/grave03_4", "textures/id1/grave03_4"},
|
|
|
|
{"textures/grave03_5", "textures/id1/grave03_5"},
|
|
|
|
{"textures/grave03_6", "textures/id1/grave03_6"},
|
|
|
|
{"textures/grave03_7", "textures/id1/grave03_7"},
|
|
|
|
{"textures/ground1_1", "textures/id1/ground1_1"},
|
|
|
|
{"textures/ground1_2", "textures/id1/ground1_2"},
|
|
|
|
{"textures/ground1_5", "textures/id1/ground1_5"},
|
|
|
|
{"textures/ground1_6", "textures/id1/ground1_6"},
|
|
|
|
{"textures/ground1_7", "textures/id1/ground1_7"},
|
|
|
|
{"textures/ground1_8", "textures/id1/ground1_8"},
|
|
|
|
{"textures/key01_1", "textures/id1/key01_1"},
|
|
|
|
{"textures/key01_2", "textures/id1/key01_2"},
|
|
|
|
{"textures/key01_3", "textures/id1/key01_3"},
|
|
|
|
{"textures/key02_1", "textures/id1/key02_1"},
|
|
|
|
{"textures/key02_2", "textures/id1/key02_2"},
|
|
|
|
{"textures/key03_1", "textures/id1/key03_1"},
|
|
|
|
{"textures/key03_2", "textures/id1/key03_2"},
|
|
|
|
{"textures/key03_3", "textures/id1/key03_3"},
|
|
|
|
{"textures/lgmetal", "textures/id1/lgmetal"},
|
|
|
|
{"textures/lgmetal2", "textures/id1/lgmetal2"},
|
|
|
|
{"textures/lgmetal3", "textures/id1/lgmetal3"},
|
|
|
|
{"textures/lgmetal4", "textures/id1/lgmetal4"},
|
|
|
|
{"textures/light1_1", "textures/id1/light1_1"},
|
|
|
|
{"textures/light1_2", "textures/id1/light1_2"},
|
|
|
|
{"textures/light1_3", "textures/id1/light1_3"},
|
|
|
|
{"textures/light1_4", "textures/id1/light1_4"},
|
|
|
|
{"textures/light1_5", "textures/id1/light1_5"},
|
|
|
|
{"textures/light1_7", "textures/id1/light1_7"},
|
|
|
|
{"textures/light1_8", "textures/id1/light1_8"},
|
|
|
|
{"textures/light3_3", "textures/id1/light3_3"},
|
|
|
|
{"textures/light3_5", "textures/id1/light3_5"},
|
|
|
|
{"textures/light3_6", "textures/id1/light3_6"},
|
|
|
|
{"textures/light3_7", "textures/id1/light3_7"},
|
|
|
|
{"textures/light3_8", "textures/id1/light3_8"},
|
|
|
|
{"textures/m5_3", "textures/id1/m5_3"},
|
|
|
|
{"textures/m5_5", "textures/id1/m5_5"},
|
|
|
|
{"textures/m5_8", "textures/id1/m5_8"},
|
|
|
|
{"textures/med100", "textures/id1/med100"},
|
|
|
|
{"textures/med3_0", "textures/id1/med3_0"},
|
|
|
|
{"textures/med3_1", "textures/id1/med3_1"},
|
|
|
|
{"textures/met5_1", "textures/id1/met5_1"},
|
|
|
|
{"textures/met5_2", "textures/id1/met5_2"},
|
|
|
|
{"textures/met5_3", "textures/id1/met5_3"},
|
|
|
|
{"textures/metal1_1", "textures/id1/metal1_1"},
|
|
|
|
{"textures/metal1_2", "textures/id1/metal1_2"},
|
|
|
|
{"textures/metal1_3", "textures/id1/metal1_3"},
|
|
|
|
{"textures/metal1_4", "textures/id1/metal1_4"},
|
|
|
|
{"textures/metal1_5", "textures/id1/metal1_5"},
|
|
|
|
{"textures/metal1_6", "textures/id1/metal1_6"},
|
|
|
|
{"textures/metal1_7", "textures/id1/metal1_7"},
|
|
|
|
{"textures/metal2_1", "textures/id1/metal2_1"},
|
|
|
|
{"textures/metal2_2", "textures/id1/metal2_2"},
|
|
|
|
{"textures/metal2_3", "textures/id1/metal2_3"},
|
|
|
|
{"textures/metal2_4", "textures/id1/metal2_4"},
|
|
|
|
{"textures/metal2_5", "textures/id1/metal2_5"},
|
|
|
|
{"textures/metal2_6", "textures/id1/metal2_6"},
|
|
|
|
{"textures/metal2_7", "textures/id1/metal2_7"},
|
|
|
|
{"textures/metal2_8", "textures/id1/metal2_8"},
|
|
|
|
{"textures/metal3_2", "textures/id1/metal3_2"},
|
|
|
|
{"textures/metal4_2", "textures/id1/metal4_2"},
|
|
|
|
{"textures/metal4_3", "textures/id1/metal4_3"},
|
|
|
|
{"textures/metal4_4", "textures/id1/metal4_4"},
|
|
|
|
{"textures/metal4_5", "textures/id1/metal4_5"},
|
|
|
|
{"textures/metal4_6", "textures/id1/metal4_6"},
|
|
|
|
{"textures/metal4_7", "textures/id1/metal4_7"},
|
|
|
|
{"textures/metal4_8", "textures/id1/metal4_8"},
|
|
|
|
{"textures/metal5_1", "textures/id1/metal5_1"},
|
|
|
|
{"textures/metal5_2", "textures/id1/metal5_2"},
|
|
|
|
{"textures/metal5_3", "textures/id1/metal5_3"},
|
|
|
|
{"textures/metal5_4", "textures/id1/metal5_4"},
|
|
|
|
{"textures/metal5_5", "textures/id1/metal5_5"},
|
|
|
|
{"textures/metal5_6", "textures/id1/metal5_6"},
|
|
|
|
{"textures/metal5_8", "textures/id1/metal5_8"},
|
|
|
|
{"textures/metal6_1", "textures/id1/metal6_1"},
|
|
|
|
{"textures/metal6_2", "textures/id1/metal6_2"},
|
|
|
|
{"textures/metal6_3", "textures/id1/metal6_3"},
|
|
|
|
{"textures/metal6_4", "textures/id1/metal6_4"},
|
|
|
|
{"textures/metalt1_1", "textures/id1/metalt1_1"},
|
|
|
|
{"textures/metalt1_2", "textures/id1/metalt1_2"},
|
|
|
|
{"textures/metalt1_7", "textures/id1/metalt1_7"},
|
|
|
|
{"textures/metalt2_1", "textures/id1/metalt2_1"},
|
|
|
|
{"textures/metalt2_2", "textures/id1/metalt2_2"},
|
|
|
|
{"textures/metalt2_3", "textures/id1/metalt2_3"},
|
|
|
|
{"textures/metalt2_4", "textures/id1/metalt2_4"},
|
|
|
|
{"textures/metalt2_5", "textures/id1/metalt2_5"},
|
|
|
|
{"textures/metalt2_6", "textures/id1/metalt2_6"},
|
|
|
|
{"textures/metalt2_7", "textures/id1/metalt2_7"},
|
|
|
|
{"textures/metalt2_8", "textures/id1/metalt2_8"},
|
|
|
|
{"textures/metflor2_1", "textures/id1/metflor2_1"},
|
|
|
|
{"textures/mmetal1_1", "textures/id1/mmetal1_1"},
|
|
|
|
{"textures/mmetal1_2", "textures/id1/mmetal1_2"},
|
|
|
|
{"textures/mmetal1_3", "textures/id1/mmetal1_3"},
|
|
|
|
{"textures/mmetal1_5", "textures/id1/mmetal1_5"},
|
|
|
|
{"textures/mmetal1_6", "textures/id1/mmetal1_6"},
|
|
|
|
{"textures/mmetal1_7", "textures/id1/mmetal1_7"},
|
|
|
|
{"textures/mmetal1_8", "textures/id1/mmetal1_8"},
|
|
|
|
{"textures/mswtch_2", "textures/id1/mswtch_2"},
|
|
|
|
{"textures/mswtch_3", "textures/id1/mswtch_3"},
|
|
|
|
{"textures/mswtch_4", "textures/id1/mswtch_4"},
|
|
|
|
{"textures/muh_bad", "textures/id1/muh_bad"},
|
|
|
|
{"textures/nail0sid", "textures/id1/nail0sid"},
|
|
|
|
{"textures/nail0top", "textures/id1/nail0top"},
|
|
|
|
{"textures/nail1sid", "textures/id1/nail1sid"},
|
|
|
|
{"textures/nail1top", "textures/id1/nail1top"},
|
|
|
|
{"textures/nmetal2_1", "textures/id1/nmetal2_1"},
|
|
|
|
{"textures/nmetal2_6", "textures/id1/nmetal2_6"},
|
|
|
|
{"textures/plat_side1", "textures/id1/plat_side1"},
|
|
|
|
{"textures/plat_stem", "textures/id1/plat_stem"},
|
|
|
|
{"textures/plat_top1", "textures/id1/plat_top1"},
|
|
|
|
{"textures/plat_top2", "textures/id1/plat_top2"},
|
|
|
|
{"textures/quake", "textures/id1/quake"},
|
|
|
|
{"textures/raven", "textures/id1/raven"},
|
|
|
|
{"textures/rock0sid", "textures/id1/rock0sid"},
|
|
|
|
{"textures/rock1_2", "textures/id1/rock1_2"},
|
|
|
|
{"textures/rock1sid", "textures/id1/rock1sid"},
|
|
|
|
{"textures/rock3_2", "textures/id1/rock3_2"},
|
|
|
|
{"textures/rock3_7", "textures/id1/rock3_7"},
|
|
|
|
{"textures/rock3_8", "textures/id1/rock3_8"},
|
|
|
|
{"textures/rock4_1", "textures/id1/rock4_1"},
|
|
|
|
{"textures/rock4_2", "textures/id1/rock4_2"},
|
|
|
|
{"textures/rock5_2", "textures/id1/rock5_2"},
|
|
|
|
{"textures/rockettop", "textures/id1/rockettop"},
|
|
|
|
{"textures/rune1_1", "textures/id1/rune1_1"},
|
|
|
|
{"textures/rune1_4", "textures/id1/rune1_4"},
|
|
|
|
{"textures/rune1_5", "textures/id1/rune1_5"},
|
|
|
|
{"textures/rune1_6", "textures/id1/rune1_6"},
|
|
|
|
{"textures/rune1_7", "textures/id1/rune1_7"},
|
|
|
|
{"textures/rune2_1", "textures/id1/rune2_1"},
|
|
|
|
{"textures/rune2_2", "textures/id1/rune2_2"},
|
|
|
|
{"textures/rune2_3", "textures/id1/rune2_3"},
|
|
|
|
{"textures/rune2_4", "textures/id1/rune2_4"},
|
|
|
|
{"textures/rune2_5", "textures/id1/rune2_5"},
|
|
|
|
{"textures/rune_a", "textures/id1/rune_a"},
|
|
|
|
{"textures/sfloor1_2", "textures/id1/sfloor1_2"},
|
|
|
|
{"textures/sfloor3_2", "textures/id1/sfloor3_2"},
|
|
|
|
{"textures/sfloor4_1", "textures/id1/sfloor4_1"},
|
|
|
|
{"textures/sfloor4_2", "textures/id1/sfloor4_2"},
|
|
|
|
{"textures/sfloor4_4", "textures/id1/sfloor4_4"},
|
|
|
|
{"textures/sfloor4_5", "textures/id1/sfloor4_5"},
|
|
|
|
{"textures/sfloor4_6", "textures/id1/sfloor4_6"},
|
|
|
|
{"textures/sfloor4_7", "textures/id1/sfloor4_7"},
|
|
|
|
{"textures/sfloor4_8", "textures/id1/sfloor4_8"},
|
|
|
|
{"textures/shot0sid", "textures/id1/shot0sid"},
|
|
|
|
{"textures/shot0top", "textures/id1/shot0top"},
|
|
|
|
{"textures/shot1sid", "textures/id1/shot1sid"},
|
|
|
|
{"textures/shot1top", "textures/id1/shot1top"},
|
|
|
|
{"textures/skill0", "textures/id1/skill0"},
|
|
|
|
{"textures/skill1", "textures/id1/skill1"},
|
|
|
|
{"textures/skill2", "textures/id1/skill2"},
|
|
|
|
{"textures/skill3", "textures/id1/skill3"},
|
|
|
|
{"textures/sky1", "textures/id1/sky1"},
|
|
|
|
{"textures/sky4", "textures/id1/sky4"},
|
|
|
|
{"textures/slip1", "textures/id1/slip1"},
|
|
|
|
{"textures/slip2", "textures/id1/slip2"},
|
|
|
|
{"textures/slipbotsd", "textures/id1/slipbotsd"},
|
|
|
|
{"textures/sliplite", "textures/id1/sliplite"},
|
|
|
|
{"textures/slipside", "textures/id1/slipside"},
|
|
|
|
{"textures/sliptopsd", "textures/id1/sliptopsd"},
|
|
|
|
{"textures/stone1_3", "textures/id1/stone1_3"},
|
|
|
|
{"textures/stone1_5", "textures/id1/stone1_5"},
|
|
|
|
{"textures/stone1_7", "textures/id1/stone1_7"},
|
|
|
|
{"textures/switch_1", "textures/id1/switch_1"},
|
|
|
|
{"textures/swtch1_1", "textures/id1/swtch1_1"},
|
|
|
|
{"textures/tech01_1", "textures/id1/tech01_1"},
|
|
|
|
{"textures/tech01_2", "textures/id1/tech01_2"},
|
|
|
|
{"textures/tech01_3", "textures/id1/tech01_3"},
|
|
|
|
{"textures/tech01_5", "textures/id1/tech01_5"},
|
|
|
|
{"textures/tech01_6", "textures/id1/tech01_6"},
|
|
|
|
{"textures/tech01_7", "textures/id1/tech01_7"},
|
|
|
|
{"textures/tech01_9", "textures/id1/tech01_9"},
|
|
|
|
{"textures/tech02_1", "textures/id1/tech02_1"},
|
|
|
|
{"textures/tech02_2", "textures/id1/tech02_2"},
|
|
|
|
{"textures/tech02_3", "textures/id1/tech02_3"},
|
|
|
|
{"textures/tech02_5", "textures/id1/tech02_5"},
|
|
|
|
{"textures/tech02_6", "textures/id1/tech02_6"},
|
|
|
|
{"textures/tech02_7", "textures/id1/tech02_7"},
|
|
|
|
{"textures/tech03_1", "textures/id1/tech03_1"},
|
|
|
|
{"textures/tech03_2", "textures/id1/tech03_2"},
|
|
|
|
{"textures/tech04_1", "textures/id1/tech04_1"},
|
|
|
|
{"textures/tech04_2", "textures/id1/tech04_2"},
|
|
|
|
{"textures/tech04_3", "textures/id1/tech04_3"},
|
|
|
|
{"textures/tech04_4", "textures/id1/tech04_4"},
|
|
|
|
{"textures/tech04_5", "textures/id1/tech04_5"},
|
|
|
|
{"textures/tech04_6", "textures/id1/tech04_6"},
|
|
|
|
{"textures/tech04_7", "textures/id1/tech04_7"},
|
|
|
|
{"textures/tech04_8", "textures/id1/tech04_8"},
|
|
|
|
{"textures/tech05_1", "textures/id1/tech05_1"},
|
|
|
|
{"textures/tech05_2", "textures/id1/tech05_2"},
|
|
|
|
{"textures/tech06_1", "textures/id1/tech06_1"},
|
|
|
|
{"textures/tech06_2", "textures/id1/tech06_2"},
|
|
|
|
{"textures/tech07_1", "textures/id1/tech07_1"},
|
|
|
|
{"textures/tech07_2", "textures/id1/tech07_2"},
|
|
|
|
{"textures/tech08_1", "textures/id1/tech08_1"},
|
|
|
|
{"textures/tech08_2", "textures/id1/tech08_2"},
|
|
|
|
{"textures/tech09_3", "textures/id1/tech09_3"},
|
|
|
|
{"textures/tech09_4", "textures/id1/tech09_4"},
|
|
|
|
{"textures/tech10_1", "textures/id1/tech10_1"},
|
|
|
|
{"textures/tech10_3", "textures/id1/tech10_3"},
|
|
|
|
{"textures/tech11_1", "textures/id1/tech11_1"},
|
|
|
|
{"textures/tech11_2", "textures/id1/tech11_2"},
|
|
|
|
{"textures/tech12_1", "textures/id1/tech12_1"},
|
|
|
|
{"textures/tech13_2", "textures/id1/tech13_2"},
|
|
|
|
{"textures/tech14_1", "textures/id1/tech14_1"},
|
|
|
|
{"textures/tech14_2", "textures/id1/tech14_2"},
|
|
|
|
{"textures/tele_top", "textures/id1/tele_top"},
|
|
|
|
{"textures/tlight01", "textures/id1/tlight01"},
|
|
|
|
{"textures/tlight01_2", "textures/id1/tlight01_2"},
|
|
|
|
{"textures/tlight02", "textures/id1/tlight02"},
|
|
|
|
{"textures/tlight03", "textures/id1/tlight03"},
|
|
|
|
{"textures/tlight05", "textures/id1/tlight05"},
|
|
|
|
{"textures/tlight07", "textures/id1/tlight07"},
|
|
|
|
{"textures/tlight08", "textures/id1/tlight08"},
|
|
|
|
{"textures/tlight09", "textures/id1/tlight09"},
|
|
|
|
{"textures/tlight10", "textures/id1/tlight10"},
|
|
|
|
{"textures/tlight11", "textures/id1/tlight11"},
|
|
|
|
{"textures/trigger", "textures/common/trigger"},
|
|
|
|
{"textures/twall1_1", "textures/id1/twall1_1"},
|
|
|
|
{"textures/twall1_2", "textures/id1/twall1_2"},
|
|
|
|
{"textures/twall1_4", "textures/id1/twall1_4"},
|
|
|
|
{"textures/twall2_1", "textures/id1/twall2_1"},
|
|
|
|
{"textures/twall2_2", "textures/id1/twall2_2"},
|
|
|
|
{"textures/twall2_3", "textures/id1/twall2_3"},
|
|
|
|
{"textures/twall2_5", "textures/id1/twall2_5"},
|
|
|
|
{"textures/twall2_6", "textures/id1/twall2_6"},
|
|
|
|
{"textures/twall3_1", "textures/id1/twall3_1"},
|
|
|
|
{"textures/twall5_1", "textures/id1/twall5_1"},
|
|
|
|
{"textures/twall5_2", "textures/id1/twall5_2"},
|
|
|
|
{"textures/twall5_3", "textures/id1/twall5_3"},
|
|
|
|
{"textures/unwall1_8", "textures/id1/unwall1_8"},
|
|
|
|
{"textures/uwall1_2", "textures/id1/uwall1_2"},
|
|
|
|
{"textures/uwall1_3", "textures/id1/uwall1_3"},
|
|
|
|
{"textures/uwall1_4", "textures/id1/uwall1_4"},
|
|
|
|
{"textures/vine1_2", "textures/id1/vine1_2"},
|
|
|
|
{"textures/wall11_2", "textures/id1/wall11_2"},
|
|
|
|
{"textures/wall11_6", "textures/id1/wall11_6"},
|
|
|
|
{"textures/wall14_5", "textures/id1/wall14_5"},
|
|
|
|
{"textures/wall14_6", "textures/id1/wall14_6"},
|
|
|
|
{"textures/wall16_7", "textures/id1/wall16_7"},
|
|
|
|
{"textures/wall3_4", "textures/id1/wall3_4"},
|
|
|
|
{"textures/wall5_4", "textures/id1/wall5_4"},
|
|
|
|
{"textures/wall9_3", "textures/id1/wall9_3"},
|
|
|
|
{"textures/wall9_8", "textures/id1/wall9_8"},
|
|
|
|
{"textures/warch05", "textures/id1/warch05"},
|
|
|
|
{"textures/wbrick1_4", "textures/id1/wbrick1_4"},
|
|
|
|
{"textures/wbrick1_5", "textures/id1/wbrick1_5"},
|
|
|
|
{"textures/wceiling4", "textures/id1/wceiling4"},
|
|
|
|
{"textures/wceiling5", "textures/id1/wceiling5"},
|
|
|
|
{"textures/wenter01", "textures/id1/wenter01"},
|
|
|
|
{"textures/wexit01", "textures/id1/wexit01"},
|
|
|
|
{"textures/wgrass1_1", "textures/id1/wgrass1_1"},
|
|
|
|
{"textures/wgrnd1_5", "textures/id1/wgrnd1_5"},
|
|
|
|
{"textures/wgrnd1_6", "textures/id1/wgrnd1_6"},
|
|
|
|
{"textures/wgrnd1_8", "textures/id1/wgrnd1_8"},
|
|
|
|
{"textures/window01_1", "textures/id1/window01_1"},
|
|
|
|
{"textures/window01_2", "textures/id1/window01_2"},
|
|
|
|
{"textures/window01_3", "textures/id1/window01_3"},
|
|
|
|
{"textures/window01_4", "textures/id1/window01_4"},
|
|
|
|
{"textures/window02_1", "textures/id1/window02_1"},
|
|
|
|
{"textures/window03", "textures/id1/window03"},
|
|
|
|
{"textures/window1_2", "textures/id1/window1_2"},
|
|
|
|
{"textures/window1_3", "textures/id1/window1_3"},
|
|
|
|
{"textures/window1_4", "textures/id1/window1_4"},
|
|
|
|
{"textures/wiz1_1", "textures/id1/wiz1_1"},
|
|
|
|
{"textures/wiz1_4", "textures/id1/wiz1_4"},
|
|
|
|
{"textures/wizmet1_1", "textures/id1/wizmet1_1"},
|
|
|
|
{"textures/wizmet1_2", "textures/id1/wizmet1_2"},
|
|
|
|
{"textures/wizmet1_3", "textures/id1/wizmet1_3"},
|
|
|
|
{"textures/wizmet1_4", "textures/id1/wizmet1_4"},
|
|
|
|
{"textures/wizmet1_5", "textures/id1/wizmet1_5"},
|
|
|
|
{"textures/wizmet1_6", "textures/id1/wizmet1_6"},
|
|
|
|
{"textures/wizmet1_7", "textures/id1/wizmet1_7"},
|
|
|
|
{"textures/wizmet1_8", "textures/id1/wizmet1_8"},
|
|
|
|
{"textures/wizwin1_2", "textures/id1/wizwin1_2"},
|
|
|
|
{"textures/wizwin1_8", "textures/id1/wizwin1_8"},
|
|
|
|
{"textures/wizwood1_2", "textures/id1/wizwood1_2"},
|
|
|
|
{"textures/wizwood1_3", "textures/id1/wizwood1_3"},
|
|
|
|
{"textures/wizwood1_4", "textures/id1/wizwood1_4"},
|
|
|
|
{"textures/wizwood1_5", "textures/id1/wizwood1_5"},
|
|
|
|
{"textures/wizwood1_6", "textures/id1/wizwood1_6"},
|
|
|
|
{"textures/wizwood1_7", "textures/id1/wizwood1_7"},
|
|
|
|
{"textures/wizwood1_8", "textures/id1/wizwood1_8"},
|
|
|
|
{"textures/wkey02_1", "textures/id1/wkey02_1"},
|
|
|
|
{"textures/wkey02_2", "textures/id1/wkey02_2"},
|
|
|
|
{"textures/wkey02_3", "textures/id1/wkey02_3"},
|
|
|
|
{"textures/wmet1_1", "textures/id1/wmet1_1"},
|
|
|
|
{"textures/wmet2_1", "textures/id1/wmet2_1"},
|
|
|
|
{"textures/wmet2_2", "textures/id1/wmet2_2"},
|
|
|
|
{"textures/wmet2_3", "textures/id1/wmet2_3"},
|
|
|
|
{"textures/wmet2_4", "textures/id1/wmet2_4"},
|
|
|
|
{"textures/wmet2_6", "textures/id1/wmet2_6"},
|
|
|
|
{"textures/wmet3_1", "textures/id1/wmet3_1"},
|
|
|
|
{"textures/wmet3_3", "textures/id1/wmet3_3"},
|
|
|
|
{"textures/wmet3_4", "textures/id1/wmet3_4"},
|
|
|
|
{"textures/wmet4_2", "textures/id1/wmet4_2"},
|
|
|
|
{"textures/wmet4_3", "textures/id1/wmet4_3"},
|
|
|
|
{"textures/wmet4_4", "textures/id1/wmet4_4"},
|
|
|
|
{"textures/wmet4_5", "textures/id1/wmet4_5"},
|
|
|
|
{"textures/wmet4_6", "textures/id1/wmet4_6"},
|
|
|
|
{"textures/wmet4_7", "textures/id1/wmet4_7"},
|
|
|
|
{"textures/wmet4_8", "textures/id1/wmet4_8"},
|
|
|
|
{"textures/wood1_1", "textures/id1/wood1_1"},
|
|
|
|
{"textures/wood1_5", "textures/id1/wood1_5"},
|
|
|
|
{"textures/wood1_7", "textures/id1/wood1_7"},
|
|
|
|
{"textures/wood1_8", "textures/id1/wood1_8"},
|
|
|
|
{"textures/woodflr1_2", "textures/id1/woodflr1_2"},
|
|
|
|
{"textures/woodflr1_4", "textures/id1/woodflr1_4"},
|
|
|
|
{"textures/woodflr1_5", "textures/id1/woodflr1_5"},
|
|
|
|
{"textures/wswamp1_2", "textures/id1/wswamp1_2"},
|
|
|
|
{"textures/wswamp1_4", "textures/id1/wswamp1_4"},
|
|
|
|
{"textures/wswamp2_1", "textures/id1/wswamp2_1"},
|
|
|
|
{"textures/wswamp2_2", "textures/id1/wswamp2_2"},
|
|
|
|
{"textures/wswitch1", "textures/id1/wswitch1"},
|
|
|
|
{"textures/wwall1_1", "textures/id1/wwall1_1"},
|
|
|
|
{"textures/wwood1_5", "textures/id1/wwood1_5"},
|
|
|
|
{"textures/wwood1_7", "textures/id1/wwood1_7"},
|
|
|
|
{"textures/z_exit", "textures/id1/z_exit"},
|
|
|
|
|
|
|
|
|
|
|
|
// TODO add more wads like prototype, Makkon et cetera
|
|
|
|
};
|
|
|
|
|
|
|
|
static const int numTextureConvertNames = sizeof( textureConvertNames ) / sizeof( textureConvertNames[0] );
|
|
|
|
|
|
|
|
void idMapFile::WadTextureToMaterial( const char* material, idStr& matName )
|
|
|
|
{
|
|
|
|
for( int i = 0 ; i < numTextureConvertNames ; i++ )
|
|
|
|
{
|
|
|
|
if( !idStr::Icmp( material, textureConvertNames[i].quakeName ) )
|
|
|
|
{
|
|
|
|
matName = textureConvertNames[i].doomName;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
matName = material;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-05 19:52:09 +00:00
|
|
|
// RB end
|