Return to Castle Wolfenstein: Tides of War (xbox) maps decompilation

010editor templates to explore the format:
Quake3Arena_BSP_Xbox_clip.bt
Quake3Arena_BSP_Xbox_world.bt

process:
get file.cachemap
unpack with cachemap_unpack.exe
place clip, world files next to file.cachemap
q3map2 -convert -format map -readxbox file.cachemap
This commit is contained in:
Garux
2026-01-12 07:46:48 +05:00
parent 182dff76ef
commit f3fd85ff22
6 changed files with 1232 additions and 11 deletions
+367
View File
@@ -0,0 +1,367 @@
LittleEndian();
// char signature[4];
// uint32 version;
// typedef struct {
// uint32 offset;
// uint32 length;
// } lump <read=ReadLumps>;
// struct {
// lump entities;
// lump shaders;
// lump planes;
// lump nodes;
// lump leafs;
// lump leafSurfaces;
// lump leafBrushes;
// lump models;
// lump brushes;
// lump brushSides;
// lump drawVerts;
// lump drawIndexes;
// lump fogs;
// lump surfaces;
// lump lightmaps;
// lump lightGrid;
// lump visibility;
// } lumps;
struct {
char name[64];
int datasize; // -8917903 4286049393
int nShaders; // 67
int offShaders; // 183238916 1
int nBSides; // 22064
int offBSides; // 183243740 2
int nPlanes; // 11400
int offPlanes; // 183508580 3
int nC; // 998 sz12
int offC; // 183736820 4
int nLeafs; // 1042 sz32
int offLeafs; // 183748796 5
int nLeafBrushes;// 7094 sz4
int offLeafbrushes;// 183782204 6
int nF; // 46 sz4
int offF; // 183810584 7
int nLeafSurfaces;// 7647 sz4
int offLeafSurfaces;// 183810768 8
int nH; // 91 sz4
int offH; // 183841356 9
int nModels; // 43 sz56
int offModels; // 184050596 16
int nBrushes; // 2437 sz44
int offBrushes; // 183841720 10
int nK; // 29184
int nL; // 456
int nM; // 64
int offM; // 183948992 ?vis 11
int nN; // 1
int nEnts; // 42492
int offEnts; // 183978176 12
int nO; // 5 sz8
int offO; // 184020668 13
int offP; // 184020708 14
int nSurfaces; // 2664
int offSurfaces;// 184020808 15 // pointer to array of pointers to cPatch_t // non-patches will be NULL
int nR; // 1
int nS; // 0
} lumps;
local int OFF = lumps.offShaders - 212;
Printf( "OFF: %d\n", OFF );
FSeek( lumps.offEnts - OFF );
char ents[lumps.nEnts];
typedef struct {
char name[64];
int surfaceFlags;
int contents;
} Shader <read=ReadShader>;
FSeek( lumps.offShaders - OFF );
Shader shader[lumps.nShaders];
typedef struct {
float normal[3];
float dist;
int idk;
} Plane <read=ReadPlanes>;
FSeek( lumps.offPlanes - OFF );
Plane planes[lumps.nPlanes];
// typedef struct {
// int plane;
// int children[2]; // Children indices. Negative numbers are leaf indices: -(leaf+1).
// int mins[3];// Integer bounding box min coord.
// int maxs[3];
// } Node <read=ReadNodes>;
// FSeek( lumps.nodes.offset);
// Node nodes[lumps.nodes.length / sizeof(Node)];
// typedef struct {
// int cluster; // Visdata cluster index.
// int area; // Areaportal area.
// // int mins[3]; // Integer bounding box min coord.
// // int maxs[3]; // Integer bounding box max coord.
// int leafbrush; // First leafbrush for leaf.
// int n_leafbrushes; // Number of leafbrushes for leaf.
// int leafface; // First leafface for leaf.
// int n_leaffaces; // Number of leaffaces for leaf.
// int mins[1]; // Integer bounding box min coord. // unused?
// int maxs[1]; // Integer bounding box max coord. // unused?
// } Leaf <read=ReadLeafs>;
typedef struct {
int cluster;
int area;
int firstLeafBrush;
int numLeafBrushes;
int firstLeafSurface;
int numLeafSurfaces;
uint leafBrush;
uint leafSurf;
} cLeaf_t;
FSeek( lumps.offLeafs - OFF );
cLeaf_t leafs[lumps.nLeafs];
FSeek( lumps.offLeafbrushes - OFF );
int leafBrushes[lumps.nLeafBrushes];
FSeek( lumps.offLeafSurfaces - OFF );
int leafSurfaces[lumps.nLeafSurfaces];
// typedef struct {
// float mins[3];
// float maxs[3];
// int face1;
// int face_n;
// int brush1;
// int brush_n;
// } Model;
typedef struct cmodel_s {
float mins[3], maxs[3];
cLeaf_t leaf; // submodels don't reference the main tree
} cmodel_t <read=ReadModels>;
FSeek( lumps.offModels - OFF );
cmodel_t models[lumps.nModels];
// typedef struct {
// int brushside; // First brushside for brush.
// int n_brushsides; // Number of brushsides for brush.
// int texture; // Texture index.
// } Brush <read=ReadBrushes>;
typedef struct {
int shaderNum; // the shader that determined the contents
int contents;
float mins[3];
float maxs[3];
int numsides;
uint sidesPTR;
int checkcount; // to avoid repeated testings
} cbrush_t;
FSeek( lumps.offBrushes - OFF );
cbrush_t brushes[lumps.nBrushes];
{
local uint umin = 4294967295, umax = 0;
local int i;
for( i = 0; i < lumps.nBrushes; ++i ){
if( (brushes[i].sidesPTR) < umin )
umin = (brushes[i].sidesPTR);
if( (brushes[i].sidesPTR) > umax )
umax = (brushes[i].sidesPTR);
}
Printf( "sidesPTR: min:%u max:%u diff:%u\n", umin, umax, umax - umin );
local int imin = 2147483647, imax = 0;
for( i = 0; i < lumps.nLeafSurfaces; ++i ){
if( (leafSurfaces[i]) < imin )
imin = (leafSurfaces[i]);
if( (leafSurfaces[i]) > imax )
imax = (leafSurfaces[i]);
}
Printf( "leafSurfaces: min:%u max:%u diff:%u\n", imin, imax, imax - imin );
imin = 2147483647, imax = 0;
for( i = 0; i < lumps.nLeafBrushes; ++i ){
if( (leafBrushes[i]) < imin )
imin = (leafBrushes[i]);
if( (leafBrushes[i]) > imax )
imax = (leafBrushes[i]);
}
Printf( "leafBrushes: min:%u max:%u diff:%u\n", imin, imax, imax - imin );
}
typedef struct {
uint planePTR; // Plane index.
int surfaceFlags;
int shaderNum; // Texture index.
} BrushSide <read=ReadBrushSides>;
FSeek( lumps.offBSides - OFF );
BrushSide brushSides[lumps.nBSides];
{
umin = 4294967295, umax = 0;
for( i = 0; i < lumps.nBSides; ++i ){
if( (brushSides[i].planePTR) < umin )
umin = (brushSides[i].planePTR);
if( (brushSides[i].planePTR) > umax )
umax = (brushSides[i].planePTR);
}
Printf( "planePTR: min:%u max:%u diff:%u\n", umin, umax, umax - umin );
}
FSeek( lumps.offSurfaces - OFF );
int surfaces[lumps.nSurfaces];
for( i = 0; i < lumps.nSurfaces; ++i ) {
if( surfaces[i] != 0 ) {
FSeek( surfaces[i] - OFF );
struct cPatch_s {
int checkcount; // to avoid repeated testings
int surfaceFlags;
int contents;
int offPatchCollide_s;
} cPatch_t;
}
}
// typedef struct {
// uint32 surfaceType;
// uint32 firstVert;
// uint32 numVerts;
// uint32 firstIndex;
// uint32 numIndexes;
// uint32 lightmapNum;
// uint32 fogNum;
// uint32 shaderNum;
// // uint32 lm_start[2];
// // uint32 lm_size[2];
// // uint32 lightmapOrigin[3];
// uint32 lightmapVecs[6]; // [9]
// uint32 patchWidth;
// uint32 patchHeight;
// } Surface <read=ReadSurfaces>;
// FSeek( lumps.surfaces.offset);
// local int surfCount = lumps.surfaces.length / sizeof(Surface);
// Surface surfaces[surfCount];
// FSeek( lumps.drawVerts.offset);
// typedef struct {
// float xyz[3]; // Vertex position.
// float st[2]; // Vertex texture coordinates.
// float lightmap[2]; // Vertex lightmap coordinates.
// //float normal[3]; // Vertex normal.
// byte color[4]; // Vertex color. RGBA. -- 1.0 is max value
// } Vertex;
// Vertex drawVerts[lumps.drawVerts.length / sizeof(Vertex) ];
// local int i, j;
// for(i=0;i<surfCount;i++) {
// if( surfaces[i].surfaceType == 2) {
// for(j=0;j<surfaces[i].numVerts;j++) {
// FSeek(lumps.drawVerts.offset+(surfaces[i].firstVert+j)*sizeof(Vertex));
// struct PATCH {
// float xyz[3];
// } patch;
// }
// }
// }
// string ReadLumps( lump &entry )
// {
// string s;
// SPrintf( s, "%d %d", entry.offset, entry.length );
// return s;
// }
string ReadShader( Shader &entry )
{
string s;
SPrintf( s, "%s", entry.name );
return s;
}
string ReadPlanes( Plane &entry )
{
string s;
SPrintf( s, "%.1f: %.1f, %.1f, %.1f", entry.dist, entry.normal[0], entry.normal[1], entry.normal[2] );
return s;
}
// string ReadNodes( Node &entry )
// {
// string s;
// SPrintf( s, "pln %d: %d, %d", entry.plane, entry.children[0], entry.children[1] );
// return s;
// }
// string ReadLeafs( Leaf &entry )
// {
// string s;
// SPrintf( s, "leaf1 %d, leafn %d, brush1 %d, brushn : %d", entry.leafface, entry.n_leaffaces, entry.leafbrush, entry.n_leafbrushes );
// return s;
// }
// string ReadBrushes( Brush &entry )
// {
// string s;
// SPrintf( s, "tex %d, brushside1 %d, brushside_n %d", entry.texture, entry.brushside, entry.n_brushsides );
// return s;
// }
string ReadBrushSides( BrushSide &entry )
{
string s;
SPrintf( s, "tex %d, plane %u", entry.shaderNum, entry.planePTR );
return s;
}
string ReadModels( cmodel_t &entry )
{
string s;
SPrintf( s, "brush %d, surf %d", entry.leaf.firstLeafBrush & 0x00FFFFFF, entry.leaf.firstLeafSurface & 0x00FFFFFF );
return s;
}
// string ReadSurfaces( Surface &entry )
// {
// string s;
// SPrintf( s, "tex: %d, type: %d", entry.shaderNum, (int)entry.surfaceType );
// return s;
// }
+416
View File
@@ -0,0 +1,416 @@
LittleEndian();
// char signature[4];
// uint32 version;
// typedef struct {
// uint32 offset;
// uint32 length;
// } lump <read=ReadLumps>;
// struct {
// lump entities;
// lump shaders;
// lump planes;
// lump nodes;
// lump leafs;
// lump leafSurfaces;
// lump leafBrushes;
// lump models;
// lump brushes;
// lump brushSides;
// lump drawVerts;
// lump drawIndexes;
// lump fogs;
// lump surfaces;
// lump lightmaps;
// lump lightGrid;
// lump visibility;
// } lumps;
struct {
char name[64]; // ie: maps/tim_dm2.bsp
char baseName[64]; // ie: tim_dm2
//---
int dataSize;
int numShaders;
uint offShaders;
int nModels; // 43 sz32
//---
uint offBmodels; // 166134168 2
int numplanes;
uint offPlanes;
int numnodes; // includes leafs
//---
int numDecisionNodes;
uint offNodes; // 167112188 4
int numsurfaces; // 2664
uint offSurfaces; // 166135544 3
//---
int nummarksurfaces;
uint offMarksurfaces; // 167242748 5
int numfogs; // 1 sz72
uint offFogs; // 166134096 1
//---
float lightGridOrigin[3];
float lightGridSize[3];
float lightGridInverseSize[3];
int lightGridBounds[3];
//---
uint offLightGridData; // 167273336 6
int numClusters;
int clusterBytes;
int idk;
//---
uint offVis; // may be passed in by CM_LoadMap to save space
int idk0[3];
//---
uint offNovis; // clusterBytes of 0xff
uint offEntityString;
int idk_0;
uint offEntityParsePoint; // 167582840 7
} lumps;
// 0166134096
// 0166134168
// 0166135544
// 0167112188
// 0167242748
// 0167273336
// 0167582840
// 2264924372
// 2265194036
// 2265634448
// 2265663632
// 2265663632
// 0026047712
// 0223740240
// 0223740312
// 0223744504
// 0227575316
// 0227906708
// 0227998340
// 0228621716
// 2264924372
// 2265808016
// 2267132688
// 2267243688
// 2267243688
local int OFF = lumps.offFogs - 288;
Printf( "OFF: %d\n", OFF );
/*
FSeek( lumps.offEnts - OFF );
char ents[lumps.nEnts];
typedef struct {
char name[64];
int surfaceFlags;
int contents;
} Shader <read=ReadShader>;
FSeek( lumps.offShaders - OFF );
Shader shader[lumps.nShaders];
typedef struct {
float normal[3];
float dist;
int idk;
} Plane <read=ReadPlanes>;
FSeek( lumps.offPlanes - OFF );
Plane planes[lumps.nPlanes];
*/
// typedef struct {
// int plane;
// int children[2]; // Children indices. Negative numbers are leaf indices: -(leaf+1).
// int mins[3];// Integer bounding box min coord.
// int maxs[3];
// } Node <read=ReadNodes>;
// FSeek( lumps.nodes.offset);
// Node nodes[lumps.nodes.length / sizeof(Node)];
// typedef struct {
// int cluster; // Visdata cluster index.
// int area; // Areaportal area.
// // int mins[3]; // Integer bounding box min coord.
// // int maxs[3]; // Integer bounding box max coord.
// int leafbrush; // First leafbrush for leaf.
// int n_leafbrushes; // Number of leafbrushes for leaf.
// int leafface; // First leafface for leaf.
// int n_leaffaces; // Number of leaffaces for leaf.
// int mins[1]; // Integer bounding box min coord. // unused?
// int maxs[1]; // Integer bounding box max coord. // unused?
// } Leaf <read=ReadLeafs>;
// FSeek( lumps.leafs.offset);
// Leaf leafs[lumps.leafs.length / sizeof(Leaf)];
// FSeek( lumps.leafSurfaces.offset);
// int leafSurfaces[lumps.leafSurfaces.length / sizeof(int)];
// FSeek( lumps.leafBrushes.offset);
// int leafBrushes[lumps.leafBrushes.length / sizeof(int)];
// typedef struct {
// float mins[3];
// float maxs[3];
// int face1;
// int face_n;
// int brush1;
// int brush_n;
// } Model;
typedef struct {
float mins[3]; // for culling
float maxs[3]; // for culling
uint offFirstSurface;
int numSurfaces;
} bmodel_t;
FSeek( lumps.offBmodels - OFF );
bmodel_t models[lumps.nModels];
// typedef struct {
// int brushside; // First brushside for brush.
// int n_brushsides; // Number of brushsides for brush.
// int texture; // Texture index.
// } Brush <read=ReadBrushes>;
/*
typedef struct {
int shaderNum; // the shader that determined the contents
int contents;
float mins[3];
float maxs[3];
int numsides;
uint sidesPTR;
int checkcount; // to avoid repeated testings
} cbrush_t;
FSeek( lumps.offBrushes - OFF );
cbrush_t brushes[lumps.nBrushes];
{
local uint bsmin = 4294967295, bsmax = 0;
local int i;
for( i = 0; i < lumps.nBrushes; ++i ){
if( (brushes[i].sidesPTR) < bsmin )
bsmin = (brushes[i].sidesPTR);
if( (brushes[i].sidesPTR) > bsmax )
bsmax = (brushes[i].sidesPTR);
}
Printf( "sidesPTR: min:%u max:%u diff:%u\n", bsmin, bsmax, bsmax - bsmin );
}
typedef struct {
uint planePTR; // Plane index.
int surfaceFlags;
int shaderNum; // Texture index.
} BrushSide <read=ReadBrushSides>;
FSeek( lumps.offBSides - OFF );
BrushSide brushSides[lumps.nBSides];
{
bsmin = 4294967295, bsmax = 0;
for( i = 0; i < lumps.nBSides; ++i ){
if( (brushSides[i].planePTR) < bsmin )
bsmin = (brushSides[i].planePTR);
if( (brushSides[i].planePTR) > bsmax )
bsmax = (brushSides[i].planePTR);
}
Printf( "planePTR: min:%u max:%u diff:%u\n", bsmin, bsmax, bsmax - bsmin );
}
*/
// typedef struct {
// uint32 surfaceType;
// uint32 firstVert;
// uint32 numVerts;
// uint32 firstIndex;
// uint32 numIndexes;
// uint32 lightmapNum;
// uint32 fogNum;
// uint32 shaderNum;
// // uint32 lm_start[2];
// // uint32 lm_size[2];
// // uint32 lightmapOrigin[3];
// uint32 lightmapVecs[6]; // [9]
// uint32 patchWidth;
// uint32 patchHeight;
// } Surface <read=ReadSurfaces>;
// FSeek( lumps.surfaces.offset);
// local int surfCount = lumps.surfaces.length / sizeof(Surface);
// Surface surfaces[surfCount];
typedef struct {
int viewCount; // if == tr.viewCount, already added
uint offShader;
int fogIndex;
int surfType;
int offSurf; // any of srf*_t
} Surface;
FSeek( lumps.offSurfaces - OFF );
Surface surfaces[lumps.numsurfaces];
{
local uint umin = 4294967295, umax = 0;
local int i;
for( i = 0; i < lumps.numsurfaces; ++i ){
if( (surfaces[i].offShader) < umin )
umin = (surfaces[i].offShader);
if( (surfaces[i].offShader) > umax )
umax = (surfaces[i].offShader);
}
Printf( "offShader: min:%u max:%u diff:%u\n", umin, umax, umax - umin );
}
// FSeek( lumps.drawVerts.offset);
typedef struct {
float xyz[3]; // Vertex position.
float st[2]; // Vertex texture coordinates.
float lightmap[2]; // Vertex lightmap coordinates.
float normal[3]; // Vertex normal.
byte color[4]; // Vertex color. RGBA. -- 1.0 is max value
} Vertex;
typedef struct {
float xyz[3]; // Vertex position.
float st[2]; // Vertex texture coordinates.
float lightmap[2]; // Vertex lightmap coordinates.
// float normal[3]; // Vertex normal.
byte color[4]; // Vertex color. RGBA. -- 1.0 is max value
} VertexPlanar;
// Vertex drawVerts[lumps.drawVerts.length / sizeof(Vertex) ];
// local int i, j;
// for(i=0;i<surfCount;i++) {
// if( surfaces[i].surfaceType == 2) {
// for(j=0;j<surfaces[i].numVerts;j++) {
// FSeek(lumps.drawVerts.offset+(surfaces[i].firstVert+j)*sizeof(Vertex));
// struct PATCH {
// float xyz[3];
// } patch;
// }
// }
// }
local int j;
for( i = 0; i < lumps.numsurfaces; ++i ) {
FSeek( surfaces[i].offSurf - OFF );
if( surfaces[i].surfType == 2 ) { // planar SF_FACE
struct PLANAR {
int surfType;
int idk[7];
int numVerts;
int numIndices;
int idk2;
VertexPlanar verts[numVerts];
int indices[numIndices];
} planar;
}
else if( surfaces[i].surfType == 3 ) { // patches SF_GRID
struct PATCH {
int surfType;
int idk[18];
int width, height;
int idk2[2];
Vertex verts[width * height]; // !! NOTE width, height may be optimized and be even
} patch;
}
else if( surfaces[i].surfType == 4 ) { // trisoup SF_TRIANGLES
struct TRISOUP {
int surfType;
int idk[11];
int numIndices;
int offIndices; // -OFF -> short
int numVerts;
int offVerts; // -OFF -> Vertex
} trisoup;
}
}
// string ReadLumps( lump &entry )
// {
// string s;
// SPrintf( s, "%d %d", entry.offset, entry.length );
// return s;
// }
/*
string ReadShader( Shader &entry )
{
string s;
SPrintf( s, "%s", entry.name );
return s;
}
string ReadPlanes( Plane &entry )
{
string s;
SPrintf( s, "%.1f: %.1f, %.1f, %.1f", entry.dist, entry.normal[0], entry.normal[1], entry.normal[2] );
return s;
}
*/
// string ReadNodes( Node &entry )
// {
// string s;
// SPrintf( s, "pln %d: %d, %d", entry.plane, entry.children[0], entry.children[1] );
// return s;
// }
// string ReadLeafs( Leaf &entry )
// {
// string s;
// SPrintf( s, "leaf1 %d, leafn %d, brush1 %d, brushn : %d", entry.leafface, entry.n_leaffaces, entry.leafbrush, entry.n_leafbrushes );
// return s;
// }
// string ReadBrushes( Brush &entry )
// {
// string s;
// SPrintf( s, "tex %d, brushside1 %d, brushside_n %d", entry.texture, entry.brushside, entry.n_brushsides );
// return s;
// }
/*
string ReadBrushSides( BrushSide &entry )
{
string s;
SPrintf( s, "tex %d, plane %u", entry.shaderNum, entry.planePTR );
return s;
}
string ReadModels( cmodel_t &entry )
{
string s;
SPrintf( s, "brush %d, surf %d", entry.leaf.firstLeafBrush & 0x00FFFFFF, entry.leaf.firstLeafSurface & 0x00FFFFFF );
return s;
}
*/
// string ReadSurfaces( Surface &entry )
// {
// string s;
// SPrintf( s, "tex: %d, type: %d", entry.shaderNum, (int)entry.surfaceType );
// return s;
// }
+426
View File
@@ -350,3 +350,429 @@ void WriteIBSPFile( const char *filename ){
/* close the file */
fclose( file );
}
using uint = std::uint32_t;
struct XbspPlane_t
{
bspPlane_t plane;
int idk;
operator bspPlane_t() const {
return plane;
}
};
struct cLeaf_t
{
int cluster;
int area;
int firstLeafBrush;
int numLeafBrushes;
int firstLeafSurface;
int numLeafSurfaces;
uint leafBrush;
uint leafSurf;
operator bspLeaf_t() const {
return bspLeaf_t{
.cluster = cluster,
.area = area,
.firstBSPLeafSurface = firstLeafSurface,
.numBSPLeafSurfaces = numLeafSurfaces,
.firstBSPLeafBrush = firstLeafBrush,
.numBSPLeafBrushes = numLeafBrushes
};
};
};
struct cmodel_t
{
MinMax minmax;
cLeaf_t leaf; // submodels don't reference the main tree
};
struct cbrush_t
{
int shaderNum; // the shader that determined the contents
int contents;
MinMax minmax;
int numsides;
uint sidesPTR;
int checkcount; // to avoid repeated testings
};
struct XBrushSide
{
uint planePTR; // Plane index.
int surfaceFlags;
int shaderNum; // Texture index.
};
struct Clip
{
char name[64];
int datasize; // -8917903 4286049393
int nShaders; // 67
int offShaders; // 183238916 1
int nBSides; // 22064
int offBSides; // 183243740 2
int nPlanes; // 11400
int offPlanes; // 183508580 3
int nC; // 998 sz12
int offC; // 183736820 4
int nLeafs; // 1042 sz32
int offLeafs; // 183748796 5
int nLeafBrushes;// 7094 sz4
int offLeafbrushes;// 183782204 6
int nF; // 46 sz4
int offF; // 183810584 7
int nLeafSurfaces;// 7647 sz4
int offLeafSurfaces;// 183810768 8
int nH; // 91 sz4
int offH; // 183841356 9
int nModels; // 43 sz56
int offModels; // 184050596 16
int nBrushes; // 2437 sz44
int offBrushes; // 183841720 10
int nK; // 29184
int nL; // 456
int nM; // 64
int offM; // 183948992 ?vis 11
int nN; // 1
int nEnts; // 42492
int offEnts; // 183978176 12
int nO; // 5 sz8
int offO; // 184020668 13
int offP; // 184020708 14
int nSurfaces; // 2664
int offSurfaces;// 184020808 15 // pointer to array of pointers to cPatch_t // non-patches will be NULL
int nR; // 1
int nS; // 0
};
struct XSurface
{
int viewCount; // if == tr.viewCount, already added
uint offShader;
int fogIndex;
int surfType;
int offSurf; // any of srf*_t
};
using XVertex = ibspDrawVert_t;
struct XVertexPlanar
{
Vector3 xyz;
Vector2 st;
Vector2 lightmap;
// Vector3 normal;
Color4b color;
operator bspDrawVert_t() const {
return bspDrawVert_t{
.xyz = xyz,
.st = st,
.lightmap{ lightmap, Vector2( 0 ), Vector2( 0 ), Vector2( 0 ) },
.normal = Vector3( 0 ),
.color { color, Color4b( 0 ), Color4b( 0 ), Color4b( 0 ) }
};
}
};
struct World
{
char name[64]; // ie: maps/tim_dm2.bsp
char baseName[64]; // ie: tim_dm2
//---
int dataSize;
int numShaders;
uint offShaders;
int nModels; // 43 sz32
//---
uint offBmodels; // 166134168 2
int numplanes;
uint offPlanes;
int numnodes; // includes leafs
//---
int numDecisionNodes;
uint offNodes; // 167112188 4
int numsurfaces; // 2664
uint offSurfaces; // 166135544 3
//---
int nummarksurfaces;
uint offMarksurfaces; // 167242748 5
int numfogs; // 1 sz72
uint offFogs; // 166134096 1
//---
float lightGridOrigin[3];
float lightGridSize[3];
float lightGridInverseSize[3];
int lightGridBounds[3];
//---
uint offLightGridData; // 167273336 6
int numClusters;
int clusterBytes;
int idk;
//---
uint offVis; // may be passed in by CM_LoadMap to save space
int idk0[3];
//---
uint offNovis; // clusterBytes of 0xff
uint offEntityString;
int idk_0;
uint offEntityParsePoint; // 167582840 7
};
void LoadXboxFile( const char *filename ){
MemBuffer fcachemap = LoadFile( filename );
MemBuffer fclip = LoadFile( StringStream( PathFilenameless( filename ), "clip" ) );
MemBuffer fworld = LoadFile( StringStream( PathFilenameless( filename ), "world" ) );
{
Clip *clip = fclip.data();
const int OFF = clip->offShaders - 212;
bspEntData = {
( char* )( (byte*)fclip.data() + clip->offEnts - OFF ),
( char* )( (byte*)fclip.data() + clip->offEnts - OFF ) + clip->nEnts
};
bspShaders = {
( bspShader_t* )( (byte*)fclip.data() + clip->offShaders - OFF ),
( bspShader_t* )( (byte*)fclip.data() + clip->offShaders - OFF ) + clip->nShaders
};
bspPlanes = {
( XbspPlane_t* )( (byte*)fclip.data() + clip->offPlanes - OFF ),
( XbspPlane_t* )( (byte*)fclip.data() + clip->offPlanes - OFF ) + clip->nPlanes
};
bspLeafSurfaces = {
( int* )( (byte*)fclip.data() + clip->offLeafSurfaces - OFF ),
( int* )( (byte*)fclip.data() + clip->offLeafSurfaces - OFF ) + clip->nLeafSurfaces
};
bspLeafBrushes = {
( int* )( (byte*)fclip.data() + clip->offLeafbrushes - OFF ),
( int* )( (byte*)fclip.data() + clip->offLeafbrushes - OFF ) + clip->nLeafBrushes
};
bspLeafs = {
( cLeaf_t* )( (byte*)fclip.data() + clip->offLeafs - OFF ),
( cLeaf_t* )( (byte*)fclip.data() + clip->offLeafs - OFF ) + clip->nLeafs
};
Span cmodels( ( cmodel_t* )( (byte*)fclip.data() + clip->offModels - OFF ), clip->nModels );
for( auto& cmodel : cmodels ){
bspModels.push_back( bspModel_t{ .minmax = cmodel.minmax,
.firstBSPSurface = 0, .numBSPSurfaces = cmodel.leaf.numLeafSurfaces,
.firstBSPBrush = 0, .numBSPBrushes = cmodel.leaf.numLeafBrushes } );
if( cmodel.leaf.numLeafSurfaces != 0 ){
bspModels.back().firstBSPSurface = *( int* )( (byte*)fclip.data() + ( cmodel.leaf.leafSurf & 0x00FFFFFF ) );
if( bspModels.front().numBSPSurfaces > bspModels.back().firstBSPSurface || bspModels.front().numBSPSurfaces == 0 ){
bspModels.front().numBSPSurfaces = bspModels.back().firstBSPSurface;
}
}
if( cmodel.leaf.numLeafBrushes != 0 ){
bspModels.back().firstBSPBrush = *( int* )( (byte*)fclip.data() + ( cmodel.leaf.leafBrush & 0x00FFFFFF ) );
if( bspModels.front().numBSPBrushes > bspModels.back().firstBSPBrush || bspModels.front().numBSPBrushes == 0 ){
bspModels.front().numBSPBrushes = bspModels.back().firstBSPBrush;
}
}
}
Span cbrushes( ( cbrush_t* )( (byte*)fclip.data() + clip->offBrushes - OFF ), clip->nBrushes );
for( auto& cbrush : cbrushes ){
bspBrushes.push_back( bspBrush_t{ .firstSide = 0, .numSides = cbrush.numsides, .shaderNum = cbrush.shaderNum } );
bspBrushes.back().firstSide = ( ( cbrush.sidesPTR & 0x00FFFFFF ) - ( clip->offBSides - OFF ) ) / sizeof( XBrushSide );
}
Span xbrushsides( ( XBrushSide* )( (byte*)fclip.data() + clip->offBSides - OFF ), clip->nBSides );
for( auto& xbs : xbrushsides ){
bspBrushSides.push_back( bspBrushSide_t{ .planeNum = 0, .shaderNum = xbs.shaderNum, .surfaceNum = 0 } );
bspBrushSides.back().planeNum = ( ( xbs.planePTR & 0x00FFFFFF ) - ( clip->offPlanes - OFF ) ) / sizeof( XbspPlane_t );
}
}
{
World *world = fworld.data();
const int OFF = world->offFogs - 288;
// note this is start of 0008.block.04
const char *shadersSatrt = std::ranges::find_if( Span( (const char*)fcachemap.data(), fcachemap.size() ), []( const char& s ){
return strEqual( &s, "<default>" );
} ).operator->() - 572;
Span xsurfs( ( XSurface* )( (byte*)fworld.data() + world->offSurfaces - OFF ), world->numsurfaces );
for( auto& xsurf : xsurfs ){
bspDrawSurface_t& surf = bspDrawSurfaces.emplace_back( bspDrawSurface_t{ .surfaceType = xsurf.surfType - 1 } );
String64 shader( shadersSatrt + ( xsurf.offShader & 0x00FFFFFF ) );
// String64 shader( (char*)fcachemap.data() + xsurf.offShader - 2193354400u );
for( size_t i = 0; i != bspShaders.size(); ++i ){
if( strEqual( shader, bspShaders[i].shader ) ){
surf.shaderNum = i;
break;
}
}
if( surf.surfaceType == MST_PLANAR ) { // planar SF_FACE
struct PLANAR {
int surfType;
int idk[7];
int numVerts;
int numIndices;
int idk2;
XVertexPlanar verts; //[numVerts];
int indices; //[numIndices];
} *planar = ( PLANAR* )( (byte*)fworld.data() + xsurf.offSurf - OFF );
surf.numVerts = planar->numVerts;
surf.numIndexes = planar->numIndices;
surf.firstVert = bspDrawVerts.size();
surf.firstIndex = bspDrawIndexes.size();
for( auto& v : Span( &planar->verts, planar->numVerts ) )
bspDrawVerts.push_back( v );
for( auto& i : Span( (int*)( &planar->verts + planar->numVerts ), planar->numIndices ) )
bspDrawIndexes.push_back( i );
}
else if( surf.surfaceType == MST_PATCH ) { // patches SF_GRID
struct PATCH {
int surfType;
int idk[18];
int width, height;
int idk2[2];
XVertex verts; //[width * height]; // !! NOTE width, height may be optimized and be even
} *patch = ( PATCH* )( (byte*)fworld.data() + xsurf.offSurf - OFF );
/* not a case in the maps */
if( ( patch->height | 1 ) >= MAX_PATCH_SIZE ){
Sys_Warning( "big patch %dx%d: ignoring\n", patch->width, patch->height );
surf.surfaceType = MST_BAD;
continue;
}
if( ( patch->width | 1 ) >= MAX_PATCH_SIZE ){
Sys_Warning( "big patch %dx%d: splitting\n", patch->width, patch->height );
mesh_t mesh( patch->width | 1, patch->height | 1 );
XVertex *v = &patch->verts;
for( int h = 0; h < patch->height; ++h ){
for( int w = 0; w < mesh.width; ++w ){
mesh[h][w] = *v;
if( !( !( patch->width & 1 ) && w == ( patch->width - 1 ) ) ){
++v;
}
}
}
if( !( patch->height & 1 ) ){
for( int w = 0; w < mesh.width; ++w )
mesh[patch->height][w] = mesh[patch->height - 1][w];
}
const int wsplit = ( mesh.width >> 1 ) | 1;
surf.patchWidth = wsplit;
surf.patchHeight = mesh.height;
surf.firstVert = bspDrawVerts.size();
for( int h = 0; h < surf.patchHeight; ++h ){
for( int w = 0; w < surf.patchWidth; ++w ){
bspDrawVerts.push_back( mesh[h][w] );
}
}
bspDrawSurface_t& surf2 = bspDrawSurfaces.emplace_back( bspDrawSurface_t( surf ) ); // avoid dead reference on realloc
surf2.patchWidth = mesh.width - ( wsplit - 1 );
surf2.patchHeight = mesh.height;
surf2.firstVert = bspDrawVerts.size();
for( int h = 0; h < surf2.patchHeight; ++h ){
for( int w = ( wsplit - 1 ); w < mesh.width; ++w ){
bspDrawVerts.push_back( mesh[h][w] );
}
}
/* fix surfaces indexing... */
const int surfidx = bspDrawSurfaces.size() - 2; // 1st patch index
// bspLeafSurfaces - skip - are not needed to decompile
for( auto& model : bspModels ){
if( model.firstBSPSurface > surfidx )
++model.firstBSPSurface;
if( model.firstBSPSurface <= surfidx
&& model.firstBSPSurface + model.numBSPSurfaces > surfidx )
++model.numBSPSurfaces;
}
continue;
}
surf.patchWidth = patch->width;
surf.patchHeight = patch->height;
surf.firstVert = bspDrawVerts.size();
if( patch->width & 1 && patch->height & 1 ){
for( auto& v : Span( &patch->verts, patch->width * patch->height ) )
bspDrawVerts.push_back( v );
}
else{
surf.patchWidth |= 1;
surf.patchHeight |= 1;
XVertex *v = &patch->verts;
for( int h = 0; h < patch->height; ++h ){
for( int w = 0; w < surf.patchWidth; ++w ){
bspDrawVerts.push_back( *v );
if( !( !( patch->width & 1 ) && w == ( patch->width - 1 ) ) ){
++v;
}
}
}
if( !( patch->height & 1 ) ){
for( int i = bspDrawVerts.size() - surf.patchWidth, end = bspDrawVerts.size(); i < end; ++i )
bspDrawVerts.push_back( bspDrawVert_t( bspDrawVerts[i] ) ); // avoid dead reference on realloc
}
}
}
else if( surf.surfaceType == MST_TRIANGLE_SOUP ) { // trisoup SF_TRIANGLES
struct TRISOUP {
int surfType;
int idk[11];
int numIndices;
int offIndices; // -OFF -> short
int numVerts;
int offVerts; // -OFF -> XVertex
} *trisoup = ( TRISOUP* )( (byte*)fworld.data() + xsurf.offSurf - OFF );
surf.numVerts = trisoup->numVerts;
surf.numIndexes = trisoup->numIndices;
surf.firstVert = bspDrawVerts.size();
surf.firstIndex = bspDrawIndexes.size();
for( auto& v : Span( ( XVertex* )( (byte*)fworld.data() + trisoup->offVerts - OFF ), trisoup->numVerts ) )
bspDrawVerts.push_back( v );
for( auto& i : Span( ( std::int16_t* )( (byte*)fworld.data() + trisoup->offIndices - OFF ), trisoup->numIndices ) )
bspDrawIndexes.push_back( i );
}
}
}
}
+2
View File
@@ -4,3 +4,5 @@
void LoadIBSPFile( const char *filename );
void WriteIBSPFile( const char *filename );
void LoadIBSPorRBSPFilePartially( const char *filename );
void LoadXboxFile( const char *filename );
+11 -1
View File
@@ -30,6 +30,7 @@
/* dependencies */
#include "q3map2.h"
#include "bspfile_ibsp.h"
@@ -1026,6 +1027,7 @@ int ConvertBSPMain( Args& args ){
map_allowed = false;
force_bsp = false;
force_map = false;
bool force_xbox = false;
/* arg checking */
if ( args.empty() ) {
@@ -1092,6 +1094,9 @@ int ConvertBSPMain( Args& args ){
while ( args.takeArg( "-readmap" ) ) {
force_map = true;
}
while ( args.takeArg( "-readxbox" ) ) {
force_xbox = true;
}
while ( args.takeArg( "-meta" ) ) {
meta = true;
}
@@ -1119,7 +1124,12 @@ int ConvertBSPMain( Args& args ){
force_bsp = true;
}
if ( force_map || ( !force_bsp && path_extension_is( source, "map" ) && map_allowed ) ) {
if( force_xbox ){
Sys_Printf( "Loading %s\n", source );
LoadXboxFile( source );
ParseEntities();
}
else if ( force_map || ( !force_bsp && path_extension_is( source, "map" ) && map_allowed ) ) {
if ( !map_allowed ) {
Sys_Warning( "the requested conversion should not be done from .map files. Compile a .bsp first.\n" );
}
+10 -10
View File
@@ -123,16 +123,16 @@ public:
continue;
}
const TriRef& vert = tri->tri;
if ( tri->surfaceType == MST_PLANAR
&& VectorCompare( vert[0]->normal, vert[1]->normal )
&& VectorCompare( vert[1]->normal, vert[2]->normal ) ) {
if ( !vector3_equal_epsilon( vert[0]->normal, buildPlane.normal(), float( nepsilon ) )
|| !vector3_equal_epsilon( vert[1]->normal, buildPlane.normal(), float( nepsilon ) )
|| !vector3_equal_epsilon( vert[2]->normal, buildPlane.normal(), float( nepsilon ) ) ) {
continue;
}
}
else
// if ( tri->surfaceType == MST_PLANAR
// && VectorCompare( vert[0]->normal, vert[1]->normal )
// && VectorCompare( vert[1]->normal, vert[2]->normal ) ) {
// if ( !vector3_equal_epsilon( vert[0]->normal, buildPlane.normal(), float( nepsilon ) )
// || !vector3_equal_epsilon( vert[1]->normal, buildPlane.normal(), float( nepsilon ) )
// || !vector3_equal_epsilon( vert[2]->normal, buildPlane.normal(), float( nepsilon ) ) ) {
// continue;
// }
// }
// else
{
// this is more prone to roundoff errors, but with embedded
// models, there is no better way