Added new .bproc format to avoid crashes with custom maps

This commit is contained in:
Robert Beckebans 2024-12-12 20:42:57 +01:00
parent 6cb57a5725
commit 5418c99b4f
5 changed files with 50 additions and 118 deletions

View file

@ -47,7 +47,7 @@ This file contains the following sections:
`RBDOOM-3-BFG is a modernization effort of DOOM-3-BFG.`
RBDOOM-3-BFG is based on DOOM-3-BFG and the goal of this port is to bring DOOM-3-BFG up to latest technology in 2023 making it closer to Doom 2016 while still remaining a DOOM 3 port regarding the gameplay.
RBDOOM-3-BFG is based on DOOM-3-BFG and the goal of this port is to bring DOOM-3-BFG up to latest technology in 2024 making it closer to Doom 2016 while still remaining a DOOM 3 port regarding the gameplay.
I started this project in 2012 and focused on making this code being future proof so other cool projects can build interesting things on top of it without the need to fix a lot of stuff first. Over 40 people all over the world contributed cool patches. Some results are:
@ -61,10 +61,12 @@ I started this project in 2012 and focused on making this code being future proo
* True internal 64 bit HDR lighting with filmic ACES tone mapping and gamma-correct rendering in linear RGB space
* Temporal Antialiasing (TAA) as a cheap alternative for MSAA and that works well with HDR and also improves PBR lighting
* Filmic post process effects like Chromatic Aberration and Dithering
* Retro Rendering modes for the nostalgia of the 8-bit and 16-bit eras including the Commodore 64, Amstrad CPC 6128, Sega Genesis and Sony PSX
* Screen Space Ambient Occlusion used to only dim down the Global Illumination contribution like in the Frostbite engine
* Bink video playback through libbinkdec (thanks to Daniel Gibson) or FFmpeg (thanks to Carl Kenner)
* Cinematic sequences can be skipped (thanks to Biel Bestué de Luna)
* Netcode fixes to allow multiplayer sessions to friends with +connect <ip of friend> (manual port forwarding required)
* Classic flashlight support
## Programming and Code Quality
* Flexible build system using CMake allowing to add optional features like FFmpeg for videos or OpenAL for sound
@ -85,12 +87,12 @@ RBDOOM-3-BFG allows mod editing and has many tiny fixes so custom content can be
* New PBR related material keywords like basecolormap, normalmap, rmaomap
* invertGreen( normalmap.png ) material keyword to allow flipping the Y-Axis for tangent space normal maps
* glTF2 .glb model support for static and skinned models (thanks to Harrie van Ginneken)
* Added back dmap and aas compilers as `standalone rbdmap.exe` tool (thanks to Pat Raynor) and improved them to work with TrenchBroom and Blender
* Standalone `rbdmap.exe` BSP compiler that has the aas navigation compiler included
* Changed dmap to support compiling maps straight from glTF2 .glb models instead of .map files using a new polygon based workflow
* Wavefront OBJ model support to make it easier getting static models from Blender/Maya/3D Studio Max into TrenchBroom
* Added in-engine Flash debugging tools and new console variables
* Added support for Mikkelsen tangent space standard for new assets (thanks to Stephen Pridham)
* Bumped the static vertex cache limit of 31 MB to roughly ~ 128 MB to help with some custom models and maps by the Doom 3 community
* Bumped the static vertex cache limit of 31 MB to roughly ~ 64 MB to help with some custom models and maps by the Doom 3 community
* com_showFPS bigger than 1 uses ImGui to show more detailed renderer stats like the original console prints with r_speeds
* .png .exr .hdr image support
* .ogg sound file support

View file

@ -45,7 +45,7 @@ idCVar idRenderModelStatic::r_slopTexCoord( "r_slopTexCoord", "0.001", CVAR_REND
idCVar idRenderModelStatic::r_slopNormal( "r_slopNormal", "0.02", CVAR_RENDERER, "merge normals that dot less than this" );
static const byte BRM_VERSION_BFG = 108;
static const byte BRM_VERSION_MOC_DATA = 109;
static const byte BRM_VERSION_MOC_DATA = 110;
static const byte BRM_VERSION = BRM_VERSION_MOC_DATA;
static const unsigned int BRM_MAGIC_BFG = ( 'B' << 24 ) | ( 'R' << 16 ) | ( 'M' << 8 ) | BRM_VERSION_BFG;
@ -441,7 +441,7 @@ bool idRenderModelStatic::LoadBinaryModel( idFile* file, const ID_TIME_T sourceT
if( magic == BRM_MAGIC_BFG )
{
int ambientViewCount = 0; // FIXME: remove
int ambientViewCount = 0;
file->ReadBig( ambientViewCount );
}
file->ReadBig( tri.generateNormals );
@ -575,19 +575,23 @@ bool idRenderModelStatic::LoadBinaryModel( idFile* file, const ID_TIME_T sourceT
tri.mocVerts = NULL;
tri.mocIndexes = NULL;
if( tri.numVerts > 0 )
int numMocVerts;
file->ReadBig( numMocVerts );
if( numMocVerts > 0 )
{
R_AllocStaticTriSurfMocVerts( &tri, tri.numVerts );
for( int j = 0; j < tri.numVerts; j++ )
R_AllocStaticTriSurfMocVerts( &tri, numMocVerts );
for( int j = 0; j < numMocVerts; j++ )
{
file->ReadVec4( tri.mocVerts[j] );
}
}
if( tri.numIndexes > 0 )
int numMocIndexes;
file->ReadBig( numMocIndexes );
if( numMocIndexes > 0 )
{
R_AllocStaticTriSurfMocIndexes( &tri, tri.numIndexes );
file->ReadBigArray( tri.mocIndexes, tri.numIndexes );
R_AllocStaticTriSurfMocIndexes( &tri, numMocIndexes );
file->ReadBigArray( tri.mocIndexes, numMocIndexes );
}
}
// RB end
@ -740,18 +744,28 @@ void idRenderModelStatic::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp
}
// RB: write Masked Occlusion data
if( tri.numVerts > 0 && tri.mocVerts != NULL )
if( tri.mocVerts != NULL )
{
file->WriteBig( tri.numVerts );
for( int j = 0; j < tri.numVerts; j++ )
{
file->WriteVec4( tri.mocVerts[ j ] );
}
}
if( tri.numIndexes > 0 && tri.mocIndexes != NULL )
else
{
file->WriteBig( ( int ) 0 );
}
if( tri.mocIndexes != NULL )
{
file->WriteBig( tri.numIndexes );
file->WriteBigArray( tri.mocIndexes, tri.numIndexes );
}
else
{
file->WriteBig( ( int ) 0 );
}
// RB end
}
}

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 2022-2023 Harrie van Ginneken
Copyright (C) 2022-2023 Robert Beckebans
Copyright (C) 2022-2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -49,7 +49,7 @@ idCVar gltf_modelSceneName( "gltf_modelSceneName", "Scene", CVAR_SYSTEM | CVAR_N
idCVar gltf_animSampleRate( "gltf_animSampleRate", "24", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NEW, "The frame rate of the converted md5anim" );
static const byte GLMB_VERSION = 103;
static const byte GLMB_VERSION = 104;
static const unsigned int GLMB_MAGIC = ( 'M' << 24 ) | ( 'L' << 16 ) | ( 'G' << 8 ) | GLMB_VERSION;
static const char* GLTF_SnapshotName = "_GLTF_Snapshot_";
static const idMat4 blenderToDoomTransform( idAngles( 0.0f, 0.0f, 90 ).ToMat3(), vec3_origin );

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015 Robert Beckebans
Copyright (C) 2015-2024 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -160,7 +160,7 @@ idRenderModel* idRenderWorldLocal::ParseModel( idLexer* src, const char* mapName
if( fileOut != NULL )
{
// write out the type so the binary reader knows what to instantiate
fileOut->WriteString( "shadowmodel" );
fileOut->WriteString( "model" );
fileOut->WriteString( token );
}
@ -328,93 +328,6 @@ idRenderModel* idRenderWorldLocal::ReadBinaryShadowModel( idFile* fileIn )
}
return NULL;
}
/*
================
idRenderWorldLocal::ParseShadowModel
NOTE: The dmap of RBDOOM-3-BFG won't generate shadowmodels.
This parsing code only applies to parse correctly legacy .proc files
================
*/
idRenderModel* idRenderWorldLocal::ParseShadowModel( idLexer* src, idFile* fileOut )
{
idToken token;
src->ExpectTokenString( "{" );
// parse the name
src->ExpectAnyToken( &token );
idRenderModel* model = renderModelManager->AllocModel();
model->InitEmpty( token );
if( fileOut != NULL )
{
// write out the type so the binary reader knows what to instantiate
fileOut->WriteString( "shadowmodel" );
fileOut->WriteString( token );
}
srfTriangles_t* tri = R_AllocStaticTriSurf();
// RB: keep compat with vanilla Doom 3 .proc files
tri->numVerts = src->ParseInt();
src->ParseInt(); // tri->numShadowIndexesNoCaps = src->ParseInt();
src->ParseInt(); //tri->numShadowIndexesNoFrontCaps = src->ParseInt();
tri->numIndexes = src->ParseInt();
src->ParseInt(); //tri->shadowCapPlaneBits = src->ParseInt();
assert( ( tri->numVerts & 1 ) == 0 );
//R_AllocStaticTriSurfPreLightShadowVerts( tri, ALIGN( tri->numVerts, 2 ) );
//tri->bounds.Clear();
for( int j = 0; j < tri->numVerts; j++ )
{
float vec[8];
src->Parse1DMatrix( 3, vec );
//tri->preLightShadowVertexes[j].xyzw[0] = vec[0];
//tri->preLightShadowVertexes[j].xyzw[1] = vec[1];
//tri->preLightShadowVertexes[j].xyzw[2] = vec[2];
//tri->preLightShadowVertexes[j].xyzw[3] = 1.0f; // no homogenous value
//tri->bounds.AddPoint( tri->preLightShadowVertexes[j].xyzw.ToVec3() );
}
// clear the last vertex if it wasn't stored
//if( ( tri->numVerts & 1 ) != 0 )
//{
// tri->preLightShadowVertexes[ALIGN( tri->numVerts, 2 ) - 1].xyzw.Zero();
//}
// RB end
// to be consistent set the number of vertices to half the number of shadow vertices
tri->numVerts = ALIGN( tri->numVerts, 2 ) / 2;
R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
for( int j = 0; j < tri->numIndexes; j++ )
{
tri->indexes[j] = src->ParseInt();
}
// add the completed surface to the model
modelSurface_t surf;
surf.id = 0;
surf.shader = tr.defaultMaterial;
surf.geometry = tri;
model->AddSurface( surf );
src->ExpectTokenString( "}" );
// NOTE: we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
if( fileOut != NULL && model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
{
model->WriteBinaryModel( fileOut, &mapTimeStamp );
}
return model;
}
/*
================
@ -574,13 +487,16 @@ void idRenderWorldLocal::ReadBinaryAreaPortals( idFile* file )
file->ReadBig( numPoints );
file->ReadBig( a1 );
file->ReadBig( a2 );
w = new( TAG_RENDER_WINDING ) idWinding( numPoints );
w->SetNumPoints( numPoints );
for( int j = 0; j < numPoints; j++ )
{
file->ReadBig( ( *w )[ j ][ 0 ] );
file->ReadBig( ( *w )[ j ][ 1 ] );
file->ReadBig( ( *w )[ j ][ 2 ] );
// no texture coordinates
( *w )[ j ][ 3 ] = 0;
( *w )[ j ][ 4 ] = 0;
@ -875,7 +791,12 @@ bool idRenderWorldLocal::InitFromMap( const char* name )
FreeWorld();
// see if we have a generated version of this
static const byte BPROC_VERSION = 1;
static const byte BPROC_VERSION_BFG = 1;
static const byte BPROC_VERSION_MOC_DATA = 2;
static const byte BPROC_VERSION = BPROC_VERSION_MOC_DATA;
static const unsigned int BPROC_MAGIC_BFG = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BPROC_VERSION_BFG;
static const unsigned int BPROC_MAGIC = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BPROC_VERSION;
bool loaded = false;
idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
@ -884,7 +805,7 @@ bool idRenderWorldLocal::InitFromMap( const char* name )
int numEntries = 0;
int magic = 0;
file->ReadBig( magic );
if( magic == BPROC_MAGIC )
if( magic == BPROC_MAGIC_BFG || magic == BPROC_MAGIC )
{
file->ReadBig( numEntries );
file->ReadString( mapName );
@ -906,8 +827,9 @@ bool idRenderWorldLocal::InitFromMap( const char* name )
renderModelManager->AddModel( lastModel );
localModels.Append( lastModel );
}
else if( type == "shadowmodel" )
else if( type == "shadowmodel" && magic == BPROC_MAGIC_BFG )
{
// RB: the original BFG .bproc just saved all models as "shadowmodel"
idRenderModel* lastModel = ReadBinaryModel( file );
if( lastModel == NULL )
{
@ -993,15 +915,10 @@ bool idRenderWorldLocal::InitFromMap( const char* name )
if( token == "shadowModel" )
{
lastModel = ParseShadowModel( src, outputFile );
// add it to the model manager list
renderModelManager->AddModel( lastModel );
// save it in the list to free when clearing this map
localModels.Append( lastModel );
numEntries++;
// RB: just parse the model but don't do anything with it
//lastModel = ParseShadowModel( src, outputFile );
src->SkipBracedSection();
lastModel = NULL;
continue;
}

View file

@ -272,7 +272,6 @@ public:
// RenderWorld_load.cpp
idRenderModel* ParseModel( idLexer* src, const char* mapName, ID_TIME_T mapTimeStamp, idFile* fileOut );
idRenderModel* ParseShadowModel( idLexer* src, idFile* fileOut );
void SetupAreaRefs();
void ParseInterAreaPortals( idLexer* src, idFile* fileOut );
void ParseNodes( idLexer* src, idFile* fileOut );