2015-04-12 09:53:54 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2021-11-09 18:47:06 +00:00
Copyright ( C ) 2015 - 2021 Robert Beckebans
2015-04-12 09:53:54 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
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
# include "../renderer/Image.h"
class OBJExporter
{
public :
struct OBJFace
{
const idMaterial * material ;
idList < idDrawVert > verts ;
idList < triIndex_t > indexes ;
} ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
struct OBJObject
{
idStr name ;
idList < OBJFace > faces ;
} ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
struct OBJGroup
{
idStr name ;
idList < OBJObject > objects ;
} ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idList < OBJGroup > groups ;
idList < const idMaterial * > materials ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
void ConvertBrushToOBJ ( OBJGroup & group , const idMapBrush * mapBrush , int entityNum , int primitiveNum , const idMat4 & transform ) ;
void ConvertPatchToOBJ ( OBJGroup & group , const idMapPatch * patch , int entityNum , int primitiveNum , const idMat4 & transform ) ;
void ConvertMeshToOBJ ( OBJGroup & group , const MapPolygonMesh * mesh , int entityNum , int primitiveNum , const idMat4 & transform ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
void Write ( const char * relativePath , const char * basePath = " fs_basepath " ) ;
} ;
void OBJExporter : : Write ( const char * relativePath , const char * basePath )
{
idStrStatic < MAX_OSPATH > convertedFileName = relativePath ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
convertedFileName . SetFileExtension ( " .obj " ) ;
idFileLocal objFile ( fileSystem - > OpenFileWrite ( convertedFileName , basePath ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
convertedFileName . SetFileExtension ( " .mtl " ) ;
idFileLocal mtlFile ( fileSystem - > OpenFileWrite ( convertedFileName , basePath ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
int totalVerts = 0 ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int g = 0 ; g < groups . Num ( ) ; g + + )
{
const OBJGroup & group = groups [ g ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
objFile - > Printf ( " g %s \n " , group . name . c_str ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int o = 0 ; o < group . objects . Num ( ) ; o + + )
{
const OBJObject & geometry = group . objects [ o ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//objFile->Printf( "g %s\n", group.name.c_str() );
//objFile->Printf( "o %s\n", geometry.name.c_str() );
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int i = 0 ; i < geometry . faces . Num ( ) ; i + + )
{
const OBJFace & face = geometry . faces [ i ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int j = 0 ; j < face . verts . Num ( ) ; j + + )
{
const idVec3 & v = face . verts [ j ] . xyz ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
objFile - > Printf ( " v %1.6f %1.6f %1.6f \n " , v . x , v . y , v . z ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int j = 0 ; j < face . verts . Num ( ) ; j + + )
{
const idVec2 & vST = face . verts [ j ] . GetTexCoord ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
objFile - > Printf ( " vt %1.6f %1.6f \n " , vST . x , vST . y ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int j = 0 ; j < face . verts . Num ( ) ; j + + )
{
const idVec3 & n = face . verts [ j ] . GetNormal ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
objFile - > Printf ( " vn %1.6f %1.6f %1.6f \n " , n . x , n . y , n . z ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//objFile->Printf( "g %s\n", group.name.c_str() );
//objFile->Printf( "o %s\n", geometry.name.c_str() );
objFile - > Printf ( " usemtl %s \n " , face . material - > GetName ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
objFile - > Printf ( " f " ) ;
//for( int j = 0; j < face.indexes.Num(); j++ )
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
// flip order for OBJ
for ( int j = face . indexes . Num ( ) - 1 ; j > = 0 ; j - - )
{
objFile - > Printf ( " %i/%i/%i " ,
face . indexes [ j ] + 1 + totalVerts ,
face . indexes [ j ] + 1 + totalVerts ,
face . indexes [ j ] + 1 + totalVerts ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
objFile - > Printf ( " \n \n " ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int i = 0 ; i < geometry . faces . Num ( ) ; i + + )
{
const OBJFace & face = geometry . faces [ i ] ;
totalVerts + = face . verts . Num ( ) ;
}
}
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int i = 0 ; i < materials . Num ( ) ; i + + )
{
const idMaterial * material = materials [ i ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
mtlFile - > Printf ( " newmtl %s \n " , material - > GetName ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( material - > GetFastPathDiffuseImage ( ) )
{
idStr path = material - > GetFastPathDiffuseImage ( ) - > GetName ( ) ;
path . SlashesToBackSlashes ( ) ;
path . DefaultFileExtension ( " .tga " ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
mtlFile - > Printf ( " \t map_Kd //.. \\ .. \\ .. \\ %s \n " , path . c_str ( ) ) ;
}
else if ( material - > GetEditorImage ( ) )
{
idStr path = material - > GetEditorImage ( ) - > GetName ( ) ;
path . SlashesToBackSlashes ( ) ;
path . DefaultFileExtension ( " .tga " ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
mtlFile - > Printf ( " \t map_Kd //.. \\ .. \\ .. \\ %s \n " , path . c_str ( ) ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
mtlFile - > Printf ( " \n " ) ;
}
}
void OBJExporter : : ConvertBrushToOBJ ( OBJGroup & group , const idMapBrush * mapBrush , int entityNum , int primitiveNum , const idMat4 & transform )
{
OBJExporter : : OBJObject & geometry = group . objects . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
geometry . name . Format ( " Primitive.%i " , primitiveNum ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +00:00
//idFixedWinding w;
idList < idFixedWinding > planeWindings ;
idBounds bounds ;
bounds . Clear ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
int numVerts = 0 ;
int numIndexes = 0 ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
bool badBrush = false ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +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:54 +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:54 +00:00
if ( ! w . GetNumPoints ( ) )
{
common - > Printf ( " Entity %i, Brush %i: base winding has no points \n " , entityNum , primitiveNum ) ;
badBrush = true ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +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:54 +00:00
if ( w . GetNumPoints ( ) < = 2 )
{
continue ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
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:54 +00:00
// allocate the surface
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +00:00
idFixedWinding & w = planeWindings [ i ] ;
if ( ! w . GetNumPoints ( ) )
{
continue ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
OBJExporter : : OBJFace & face = geometry . faces . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
face . material = declManager - > FindMaterial ( mapSide - > GetMaterial ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int j = 0 ; j < w . GetNumPoints ( ) ; j + + )
{
idDrawVert & dv = face . verts . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
const idVec3 & xyz = w [ j ] . ToVec3 ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
dv . xyz = ( transform * idVec4 ( xyz . x , xyz . y , xyz . z , 1 ) ) . ToVec3 ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +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
2021-03-12 17:13:33 +00:00
// RB: support Valve 220 projection
if ( ( mapSide - > GetProjectionType ( ) = = idMapBrushSide : : PROJECTION_VALVE220 ) )
{
const idMaterial * material = declManager - > FindMaterial ( mapSide - > GetMaterial ( ) ) ;
// RB: TODO
idVec2i texSize ;
idImage * image = material - > GetEditorImage ( ) ;
if ( image ! = NULL )
{
texSize . x = image - > GetUploadWidth ( ) ;
texSize . y = image - > GetUploadHeight ( ) ;
}
else
{
texSize = mapSide - > GetTextureSize ( ) ;
}
st . x / = texSize . x ;
st . y / = texSize . y ;
}
2015-04-12 09:53:54 +00:00
// flip y
st . y = 1.0f - st . y ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
dv . SetTexCoord ( st ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
// copy normal
dv . SetNormal ( transform * mapSide - > GetPlane ( ) . Normal ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +00:00
#if 0
// triangulate
for ( int j = 1 ; j < w . GetNumPoints ( ) - 1 ; j + + )
{
face . indexes . Append ( numVerts ) ;
face . indexes . Append ( numVerts + j ) ;
face . indexes . Append ( numVerts + j + 1 ) ;
}
# else
// export n-gon
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//for( int j = 0; j < w.GetNumPoints(); j++ )
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
// reverse order, so normal does not point inwards
for ( int j = w . GetNumPoints ( ) - 1 ; j > = 0 ; j - - )
{
face . indexes . Append ( numVerts + j ) ;
}
# endif
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
numVerts + = w . GetNumPoints ( ) ;
}
}
void OBJExporter : : ConvertPatchToOBJ ( OBJGroup & group , const idMapPatch * patch , int entityNum , int primitiveNum , const idMat4 & transform )
{
OBJExporter : : OBJObject & geometry = group . objects . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
geometry . name . Format ( " Primitive.%i " , primitiveNum ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idSurface_Patch * cp = new idSurface_Patch ( * patch ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +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:54 +00:00
const idMaterial * material = declManager - > FindMaterial ( patch - > GetMaterial ( ) ) ;
materials . AddUnique ( material ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int i = 0 ; i < cp - > GetNumIndexes ( ) ; i + = 3 )
{
OBJExporter : : OBJFace & face = geometry . faces . Alloc ( ) ;
face . material = material ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idDrawVert & dv0 = face . verts . Alloc ( ) ;
idDrawVert & dv1 = face . verts . Alloc ( ) ;
idDrawVert & dv2 = face . verts . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
dv0 = ( * cp ) [ cp - > GetIndexes ( ) [ i + 1 ] ] ;
dv1 = ( * cp ) [ cp - > GetIndexes ( ) [ i + 2 ] ] ;
dv2 = ( * cp ) [ cp - > GetIndexes ( ) [ i + 0 ] ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
dv0 . xyz = ( transform * idVec4 ( dv0 . xyz . x , dv0 . xyz . y , dv0 . xyz . z , 1 ) ) . ToVec3 ( ) ;
dv1 . xyz = ( transform * idVec4 ( dv1 . xyz . x , dv1 . xyz . y , dv1 . xyz . z , 1 ) ) . ToVec3 ( ) ;
dv2 . xyz = ( transform * idVec4 ( dv2 . xyz . x , dv2 . xyz . y , dv2 . xyz . z , 1 ) ) . ToVec3 ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//face.indexes.Append( cp->GetIndexes()[i + 0] );
//face.indexes.Append( cp->GetIndexes()[i + 1] );
//face.indexes.Append( cp->GetIndexes()[i + 2] );
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
face . indexes . Append ( i + 0 ) ;
face . indexes . Append ( i + 1 ) ;
face . indexes . Append ( i + 2 ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
delete cp ;
}
void OBJExporter : : ConvertMeshToOBJ ( OBJGroup & group , const MapPolygonMesh * mesh , int entityNum , int primitiveNum , const idMat4 & transform )
{
OBJExporter : : OBJObject & geometry = group . objects . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
geometry . name . Format ( " Primitive.%i " , primitiveNum ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
const idList < idDrawVert > & verts = mesh - > GetDrawVerts ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
int numVerts = 0 ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int i = 0 ; i < mesh - > GetNumPolygons ( ) ; i + + )
{
2016-03-05 19:52:09 +00:00
const MapPolygon & poly = mesh - > GetFace ( i ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
const idMaterial * material = declManager - > FindMaterial ( poly . GetMaterial ( ) ) ;
2015-04-12 09:53:54 +00:00
materials . AddUnique ( material ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
OBJExporter : : OBJFace & face = geometry . faces . Alloc ( ) ;
face . material = material ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
const idList < int > & indexes = poly . GetIndexes ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int j = 0 ; j < verts . Num ( ) ; j + + )
{
idDrawVert & dv = face . verts . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
dv = verts [ j ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
dv . xyz = ( transform * idVec4 ( dv . xyz . x , dv . xyz . y , dv . xyz . z , 1 ) ) . ToVec3 ( ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
#if 0
//for( int j = 0; j < indexes.Num(); j++ )
for ( int j = 1 ; j < indexes . Num ( ) - 1 ; j + + )
{
int index = indexes [ j ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//face.indexes.Append( j );
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
face . indexes . Append ( numVerts + j + 1 ) ;
face . indexes . Append ( numVerts + j ) ;
face . indexes . Append ( numVerts ) ;
}
# else
for ( int j = 0 ; j < indexes . Num ( ) ; j + + )
{
int index = indexes [ j ] ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
face . indexes . Append ( numVerts + index ) ;
}
# endif
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
numVerts + = verts . Num ( ) ;
}
}
CONSOLE_COMMAND ( exportMapToOBJ , " Convert .map file to .obj/.mtl " , idCmdSystem : : ArgCompletion_MapName )
{
common - > SetRefreshOnPrint ( true ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( args . Argc ( ) ! = 2 )
{
common - > Printf ( " Usage: exportMapToOBJ <map> \n " ) ;
return ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStr filename = args . Argv ( 1 ) ;
if ( ! filename . Length ( ) )
{
return ;
}
filename . StripFileExtension ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStr mapName ;
sprintf ( mapName , " maps/%s.map " , filename . c_str ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idMapFile map ;
if ( map . Parse ( mapName , false , false ) )
{
OBJExporter exporter ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
int count = map . GetNumEntities ( ) ;
for ( int j = 0 ; j < count ; j + + )
{
idMapEntity * ent = map . GetEntity ( j ) ;
if ( ent )
{
idStr classname = ent - > epairs . GetString ( " classname " ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idVec3 origin ;
origin . Zero ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idMat3 rot ;
rot . Identity ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( ent - > GetNumPrimitives ( ) )
{
OBJExporter : : OBJGroup & group = exporter . groups . Alloc ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( classname = = " worldspawn " )
{
group . name = " BSP " ;
}
else
{
group . name = ent - > epairs . GetString ( " name " ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
origin = ent - > epairs . GetVector ( " origin " , " 0 0 0 " ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( ! ent - > epairs . GetMatrix ( " rotation " , " 1 0 0 0 1 0 0 0 1 " , rot ) )
{
float angle = ent - > epairs . GetFloat ( " angle " ) ;
if ( angle ! = 0.0f )
{
rot = idAngles ( 0.0f , angle , 0.0f ) . ToMat3 ( ) ;
}
else
{
rot . Identity ( ) ;
}
}
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idMat4 transform ( rot , origin ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
for ( int i = 0 ; i < ent - > GetNumPrimitives ( ) ; i + + )
{
idMapPrimitive * mapPrim ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
mapPrim = ent - > GetPrimitive ( i ) ;
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_BRUSH )
{
exporter . ConvertBrushToOBJ ( group , static_cast < idMapBrush * > ( mapPrim ) , j , i , transform ) ;
continue ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_PATCH )
{
exporter . ConvertPatchToOBJ ( group , static_cast < idMapPatch * > ( mapPrim ) , j , i , transform ) ;
continue ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( mapPrim - > GetType ( ) = = idMapPrimitive : : TYPE_MESH )
{
exporter . ConvertMeshToOBJ ( group , static_cast < MapPolygonMesh * > ( mapPrim ) , j , i , transform ) ;
continue ;
}
}
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//Hack: for info_location
/*
bool hasLocation = false ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrList * list ;
listHash . Get ( classname , & list ) ;
if ( list )
{
for ( int k = 0 ; k < list - > Num ( ) ; k + + )
{
idStr val = ent - > epairs . GetString ( ( * list ) [ k ] , " " ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( val . Length ( ) & & classname = = " info_location " & & ( * list ) [ k ] = = " location " )
{
hasLocation = true ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( val . Length ( ) & & TestMapVal ( val ) )
{
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( ! hasLocation | | ( * list ) [ k ] = = " location " )
{
//Localize it!!!
strCount + + ;
ent - > epairs . Set ( ( * list ) [ k ] , langDict . AddString ( val ) ) ;
}
}
}
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
*/
}
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrStatic < MAX_OSPATH > canonical = mapName ;
canonical . ToLower ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrStatic < MAX_OSPATH > extension ;
canonical . ExtractFileExtension ( extension ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrStatic < MAX_OSPATH > convertedFileName ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
//convertedFileName = "converted/";
convertedFileName = canonical ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
exporter . Write ( convertedFileName ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
common - > SetRefreshOnPrint ( false ) ;
}
2020-03-31 19:01:44 +00:00
CONSOLE_COMMAND ( convertMap , " Convert .map file to new map format with polygons instead of brushes " , idCmdSystem : : ArgCompletion_MapNameNoJson )
2015-04-12 09:53:54 +00:00
{
common - > SetRefreshOnPrint ( true ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
if ( args . Argc ( ) ! = 2 )
{
common - > Printf ( " Usage: convertMap <map> \n " ) ;
return ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStr filename = args . Argv ( 1 ) ;
if ( ! filename . Length ( ) )
{
return ;
}
filename . StripFileExtension ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStr mapName ;
sprintf ( mapName , " maps/%s.map " , filename . c_str ( ) ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idMapFile map ;
2018-11-03 13:36:03 +00:00
if ( map . Parse ( mapName , true , false ) )
2015-04-12 09:53:54 +00:00
{
map . ConvertToPolygonMeshFormat ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrStatic < MAX_OSPATH > canonical = mapName ;
canonical . ToLower ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrStatic < MAX_OSPATH > extension ;
canonical . StripFileExtension ( ) ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
idStrStatic < MAX_OSPATH > convertedFileName ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
convertedFileName = canonical ;
convertedFileName + = " _converted " ;
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
map . Write ( convertedFileName , " .map " ) ;
}
2019-11-11 19:27:44 +00:00
2015-04-12 09:53:54 +00:00
common - > SetRefreshOnPrint ( false ) ;
2016-03-05 19:52:09 +00:00
}
2020-03-31 19:01:44 +00:00
CONSOLE_COMMAND ( convertMapToJSON , " Convert .map file to new .json map format with polygons instead of brushes " , idCmdSystem : : ArgCompletion_MapNameNoJson )
2016-03-05 19:52:09 +00:00
{
common - > SetRefreshOnPrint ( true ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
if ( args . Argc ( ) ! = 2 )
{
common - > Printf ( " Usage: convertMapToJSON <map> \n " ) ;
return ;
}
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
idStr filename = args . Argv ( 1 ) ;
if ( ! filename . Length ( ) )
{
return ;
}
filename . StripFileExtension ( ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
idStr mapName ;
sprintf ( mapName , " maps/%s.map " , filename . c_str ( ) ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
idMapFile map ;
2018-11-03 13:36:03 +00:00
if ( map . Parse ( mapName , true , false ) )
2016-03-05 19:52:09 +00:00
{
map . ConvertToPolygonMeshFormat ( ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
idStrStatic < MAX_OSPATH > canonical = mapName ;
canonical . ToLower ( ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
idStrStatic < MAX_OSPATH > extension ;
canonical . StripFileExtension ( ) ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
idStrStatic < MAX_OSPATH > convertedFileName ;
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
convertedFileName = canonical ;
//convertedFileName += "_converted";
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
map . WriteJSON ( convertedFileName , " .json " ) ;
}
2019-11-11 19:27:44 +00:00
2016-03-05 19:52:09 +00:00
common - > SetRefreshOnPrint ( false ) ;
}
2021-11-09 18:47:06 +00:00
2024-05-11 18:42:22 +00:00
CONSOLE_COMMAND_SHIP ( convertMapToValve220 , " Convert .map file to the Valve 220 map format for TrenchBroom " , idCmdSystem : : ArgCompletion_MapNameNoJson )
2021-11-09 18:47:06 +00:00
{
common - > SetRefreshOnPrint ( true ) ;
if ( args . Argc ( ) ! = 2 )
{
common - > Printf ( " Usage: convertMapToValve220 <map> \n " ) ;
return ;
}
idStr filename = args . Argv ( 1 ) ;
if ( ! filename . Length ( ) )
{
return ;
}
filename . StripFileExtension ( ) ;
idStr mapName ;
sprintf ( mapName , " maps/%s.map " , filename . c_str ( ) ) ;
idMapFile map ;
if ( map . Parse ( mapName , true , false ) )
{
2022-01-20 21:25:06 +00:00
// make sure we have access to all .bimage files for that map
fileSystem - > BeginLevelLoad ( filename , NULL , 0 ) ;
2025-01-23 22:08:57 +00:00
map . ConvertToValve220Format ( true ) ;
2021-11-09 18:47:06 +00:00
2022-01-20 21:25:06 +00:00
fileSystem - > EndLevelLoad ( ) ;
2021-11-09 18:47:06 +00:00
idStrStatic < MAX_OSPATH > canonical = mapName ;
canonical . ToLower ( ) ;
idStrStatic < MAX_OSPATH > extension ;
canonical . StripFileExtension ( ) ;
idStrStatic < MAX_OSPATH > convertedFileName ;
convertedFileName = canonical ;
convertedFileName + = " _valve220 " ;
map . Write ( convertedFileName , " .map " ) ;
}
common - > SetRefreshOnPrint ( false ) ;
}
2022-02-05 14:49:50 +00:00
2023-10-25 23:52:03 +00:00
CONSOLE_COMMAND ( checkMapsForBrushEntities , " List all brush entities in all .map files " , idCmdSystem : : ArgCompletion_MapNameNoJson )
{
//int totalImagesCount = 0;
idFileList * files = fileSystem - > ListFilesTree ( " maps/game " , " .map " , true , true ) ;
idDict classTypeOverview ;
for ( int f = 0 ; f < files - > GetList ( ) . Num ( ) ; f + + )
{
idStr mapName = files - > GetList ( ) [ f ] ;
idMapFile map ;
if ( map . Parse ( mapName , true , false ) )
{
map . ClassifyEntitiesForTrenchBroom ( classTypeOverview ) ;
}
}
fileSystem - > FreeFileList ( files ) ;
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 ( " \n PointClasses: \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 ( " \n MixedClasses: \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 ( ) ) ;
}
}
}
2022-02-05 14:49:50 +00:00
2024-05-11 18:42:22 +00:00
CONSOLE_COMMAND_SHIP ( convertMapQuakeToDoom , " Convert Quake .map in Valve 220 map format for Doom 3 BFG " , idCmdSystem : : ArgCompletion_MapNameNoJson )
2022-02-05 14:49:50 +00:00
{
common - > SetRefreshOnPrint ( true ) ;
if ( args . Argc ( ) ! = 2 )
{
common - > Printf ( " Usage: convertMapQuakeToDoom <map> \n " ) ;
return ;
}
idStr filename = args . Argv ( 1 ) ;
if ( ! filename . Length ( ) )
{
return ;
}
filename . StripFileExtension ( ) ;
idStr mapName ;
sprintf ( mapName , " maps/%s.map " , filename . c_str ( ) ) ;
idMapFile map ;
if ( map . Parse ( mapName , true , false ) )
{
map . ConvertQuakeToDoom ( ) ;
idStrStatic < MAX_OSPATH > canonical = mapName ;
canonical . ToLower ( ) ;
idStrStatic < MAX_OSPATH > extension ;
canonical . StripFileExtension ( ) ;
//idStrStatic< MAX_OSPATH > convertedFileName;
//convertedFileName = canonical;
//convertedFileName += "_valve220";
map . Write ( canonical , " .map " ) ;
}
common - > SetRefreshOnPrint ( false ) ;
}