doom3-bfg/neo/framework/Common_mapconvert.cpp

842 lines
20 KiB
C++
Raw Normal View History

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015-2021 Robert Beckebans
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
struct OBJObject
{
idStr name;
idList<OBJFace> faces;
};
2019-11-11 19:27:44 +00:00
struct OBJGroup
{
idStr name;
idList<OBJObject> objects;
};
2019-11-11 19:27:44 +00:00
idList<OBJGroup> groups;
idList< const idMaterial* > materials;
2019-11-11 19:27:44 +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
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
convertedFileName.SetFileExtension( ".obj" );
idFileLocal objFile( fileSystem->OpenFileWrite( convertedFileName, basePath ) );
2019-11-11 19:27:44 +00:00
convertedFileName.SetFileExtension( ".mtl" );
idFileLocal mtlFile( fileSystem->OpenFileWrite( convertedFileName, basePath ) );
2019-11-11 19:27:44 +00:00
int totalVerts = 0;
2019-11-11 19:27:44 +00:00
for( int g = 0; g < groups.Num(); g++ )
{
const OBJGroup& group = groups[g];
2019-11-11 19:27:44 +00:00
objFile->Printf( "g %s\n", group.name.c_str() );
2019-11-11 19:27:44 +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
//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
for( int i = 0; i < geometry.faces.Num(); i++ )
{
const OBJFace& face = geometry.faces[i];
2019-11-11 19:27:44 +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
objFile->Printf( "v %1.6f %1.6f %1.6f\n", v.x, v.y, v.z );
}
2019-11-11 19:27:44 +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
objFile->Printf( "vt %1.6f %1.6f\n", vST.x, vST.y );
}
2019-11-11 19:27:44 +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
objFile->Printf( "vn %1.6f %1.6f %1.6f\n", n.x, n.y, n.z );
}
2019-11-11 19:27:44 +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
objFile->Printf( "f " );
//for( int j = 0; j < face.indexes.Num(); j++ )
2019-11-11 19:27:44 +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
objFile->Printf( "\n\n" );
}
2019-11-11 19:27:44 +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
for( int i = 0; i < materials.Num(); i++ )
{
const idMaterial* material = materials[i];
2019-11-11 19:27:44 +00:00
mtlFile->Printf( "newmtl %s\n", material->GetName() );
2019-11-11 19:27:44 +00:00
if( material->GetFastPathDiffuseImage() )
{
idStr path = material->GetFastPathDiffuseImage()->GetName();
path.SlashesToBackSlashes();
path.DefaultFileExtension( ".tga" );
2019-11-11 19:27:44 +00:00
mtlFile->Printf( "\tmap_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
mtlFile->Printf( "\tmap_Kd //..\\..\\..\\%s\n", path.c_str() );
}
2019-11-11 19:27:44 +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
geometry.name.Format( "Primitive.%i", primitiveNum );
2019-11-11 19:27:44 +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
//idFixedWinding w;
idList<idFixedWinding> planeWindings;
idBounds bounds;
bounds.Clear();
2019-11-11 19:27:44 +00:00
int numVerts = 0;
int numIndexes = 0;
2019-11-11 19:27:44 +00:00
bool badBrush = false;
2019-11-11 19:27:44 +00:00
for( int i = 0; i < mapBrush->GetNumSides(); i++ )
{
idMapBrushSide* mapSide = mapBrush->GetSide( i );
2019-11-11 19:27:44 +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
// chop base plane by other brush sides
idFixedWinding& w = planeWindings.Alloc();
w.BaseForPlane( -planes[i] );
2019-11-11 19:27:44 +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
for( int j = 0; j < mapBrush->GetNumSides() && w.GetNumPoints(); j++ )
{
if( i == j )
{
continue;
}
2019-11-11 19:27:44 +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
if( w.GetNumPoints() <= 2 )
{
continue;
}
2019-11-11 19:27:44 +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
// allocate the surface
2019-11-11 19:27:44 +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
idFixedWinding& w = planeWindings[i];
if( !w.GetNumPoints() )
{
continue;
}
2019-11-11 19:27:44 +00:00
OBJExporter::OBJFace& face = geometry.faces.Alloc();
2019-11-11 19:27:44 +00:00
face.material = declManager->FindMaterial( mapSide->GetMaterial() );
2019-11-11 19:27:44 +00:00
for( int j = 0; j < w.GetNumPoints(); j++ )
{
idDrawVert& dv = face.verts.Alloc();
2019-11-11 19:27:44 +00:00
const idVec3& xyz = w[j].ToVec3();
2019-11-11 19:27:44 +00:00
dv.xyz = ( transform * idVec4( xyz.x, xyz.y, xyz.z, 1 ) ).ToVec3();
2019-11-11 19:27:44 +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
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
// 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;
}
// flip y
st.y = 1.0f - st.y;
2019-11-11 19:27:44 +00:00
dv.SetTexCoord( st );
2019-11-11 19:27:44 +00:00
// copy normal
dv.SetNormal( transform * mapSide->GetPlane().Normal() );
2019-11-11 19:27:44 +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
#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
//for( int j = 0; j < w.GetNumPoints(); j++ )
2019-11-11 19:27:44 +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
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
geometry.name.Format( "Primitive.%i", primitiveNum );
2019-11-11 19:27:44 +00:00
idSurface_Patch* cp = new idSurface_Patch( *patch );
2019-11-11 19:27:44 +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
const idMaterial* material = declManager->FindMaterial( patch->GetMaterial() );
materials.AddUnique( material );
2019-11-11 19:27:44 +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
idDrawVert& dv0 = face.verts.Alloc();
idDrawVert& dv1 = face.verts.Alloc();
idDrawVert& dv2 = face.verts.Alloc();
2019-11-11 19:27:44 +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
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
//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
face.indexes.Append( i + 0 );
face.indexes.Append( i + 1 );
face.indexes.Append( i + 2 );
}
2019-11-11 19:27:44 +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
geometry.name.Format( "Primitive.%i", primitiveNum );
2019-11-11 19:27:44 +00:00
const idList<idDrawVert>& verts = mesh->GetDrawVerts();
2019-11-11 19:27:44 +00:00
int numVerts = 0;
2019-11-11 19:27:44 +00:00
for( int i = 0; i < mesh->GetNumPolygons(); i++ )
{
const MapPolygon& poly = mesh->GetFace( i );
2019-11-11 19:27:44 +00:00
const idMaterial* material = declManager->FindMaterial( poly.GetMaterial() );
materials.AddUnique( material );
2019-11-11 19:27:44 +00:00
OBJExporter::OBJFace& face = geometry.faces.Alloc();
face.material = material;
2019-11-11 19:27:44 +00:00
const idList<int>& indexes = poly.GetIndexes();
2019-11-11 19:27:44 +00:00
for( int j = 0; j < verts.Num(); j++ )
{
idDrawVert& dv = face.verts.Alloc();
2019-11-11 19:27:44 +00:00
dv = verts[j];
2019-11-11 19:27:44 +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
#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
//face.indexes.Append( j );
2019-11-11 19:27:44 +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
face.indexes.Append( numVerts + index );
}
#endif
2019-11-11 19:27:44 +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
if( args.Argc() != 2 )
{
common->Printf( "Usage: exportMapToOBJ <map>\n" );
return;
}
2019-11-11 19:27:44 +00:00
idStr filename = args.Argv( 1 );
if( !filename.Length() )
{
return;
}
filename.StripFileExtension();
2019-11-11 19:27:44 +00:00
idStr mapName;
sprintf( mapName, "maps/%s.map", filename.c_str() );
2019-11-11 19:27:44 +00:00
idMapFile map;
if( map.Parse( mapName, false, false ) )
{
OBJExporter exporter;
2019-11-11 19:27:44 +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
idVec3 origin;
origin.Zero();
2019-11-11 19:27:44 +00:00
idMat3 rot;
rot.Identity();
2019-11-11 19:27:44 +00:00
if( ent->GetNumPrimitives() )
{
OBJExporter::OBJGroup& group = exporter.groups.Alloc();
2019-11-11 19:27:44 +00:00
if( classname == "worldspawn" )
{
group.name = "BSP";
}
else
{
group.name = ent->epairs.GetString( "name" );
2019-11-11 19:27:44 +00:00
origin = ent->epairs.GetVector( "origin", "0 0 0" );
2019-11-11 19:27:44 +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
idMat4 transform( rot, origin );
2019-11-11 19:27:44 +00:00
for( int i = 0; i < ent->GetNumPrimitives(); i++ )
{
idMapPrimitive* mapPrim;
2019-11-11 19:27:44 +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
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
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
//Hack: for info_location
/*
bool hasLocation = false;
2019-11-11 19:27:44 +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
if( val.Length() && classname == "info_location" && ( *list )[k] == "location" )
{
hasLocation = true;
}
2019-11-11 19:27:44 +00:00
if( val.Length() && TestMapVal( val ) )
{
2019-11-11 19:27:44 +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
*/
}
}
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > canonical = mapName;
canonical.ToLower();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > extension;
canonical.ExtractFileExtension( extension );
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > convertedFileName;
2019-11-11 19:27:44 +00:00
//convertedFileName = "converted/";
convertedFileName = canonical;
2019-11-11 19:27:44 +00:00
exporter.Write( convertedFileName );
}
2019-11-11 19:27:44 +00:00
common->SetRefreshOnPrint( false );
}
CONSOLE_COMMAND( convertMap, "Convert .map file to new map format with polygons instead of brushes", idCmdSystem::ArgCompletion_MapNameNoJson )
{
common->SetRefreshOnPrint( true );
2019-11-11 19:27:44 +00:00
if( args.Argc() != 2 )
{
common->Printf( "Usage: convertMap <map>\n" );
return;
}
2019-11-11 19:27:44 +00:00
idStr filename = args.Argv( 1 );
if( !filename.Length() )
{
return;
}
filename.StripFileExtension();
2019-11-11 19:27:44 +00:00
idStr mapName;
sprintf( mapName, "maps/%s.map", filename.c_str() );
2019-11-11 19:27:44 +00:00
idMapFile map;
if( map.Parse( mapName, true, false ) )
{
map.ConvertToPolygonMeshFormat();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > canonical = mapName;
canonical.ToLower();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > extension;
canonical.StripFileExtension();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > convertedFileName;
2019-11-11 19:27:44 +00:00
convertedFileName = canonical;
convertedFileName += "_converted";
2019-11-11 19:27:44 +00:00
map.Write( convertedFileName, ".map" );
}
2019-11-11 19:27:44 +00:00
common->SetRefreshOnPrint( false );
}
CONSOLE_COMMAND( convertMapToJSON, "Convert .map file to new .json map format with polygons instead of brushes", idCmdSystem::ArgCompletion_MapNameNoJson )
{
common->SetRefreshOnPrint( true );
2019-11-11 19:27:44 +00:00
if( args.Argc() != 2 )
{
common->Printf( "Usage: convertMapToJSON <map>\n" );
return;
}
2019-11-11 19:27:44 +00:00
idStr filename = args.Argv( 1 );
if( !filename.Length() )
{
return;
}
filename.StripFileExtension();
2019-11-11 19:27:44 +00:00
idStr mapName;
sprintf( mapName, "maps/%s.map", filename.c_str() );
2019-11-11 19:27:44 +00:00
idMapFile map;
if( map.Parse( mapName, true, false ) )
{
map.ConvertToPolygonMeshFormat();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > canonical = mapName;
canonical.ToLower();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > extension;
canonical.StripFileExtension();
2019-11-11 19:27:44 +00:00
idStrStatic< MAX_OSPATH > convertedFileName;
2019-11-11 19:27:44 +00:00
convertedFileName = canonical;
//convertedFileName += "_converted";
2019-11-11 19:27:44 +00:00
map.WriteJSON( convertedFileName, ".json" );
}
2019-11-11 19:27:44 +00:00
common->SetRefreshOnPrint( false );
}
CONSOLE_COMMAND_SHIP( convertMapToValve220, "Convert .map file to the Valve 220 map format for TrenchBroom", idCmdSystem::ArgCompletion_MapNameNoJson )
{
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 );
map.ConvertToValve220Format( true );
2022-01-20 21:25:06 +00:00
fileSystem->EndLevelLoad();
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
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( "\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() );
}
}
}
2022-02-05 14:49:50 +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 );
}