diff --git a/tools/quake3/Quake3Arena_BSP_Xbox_clip.bt b/tools/quake3/Quake3Arena_BSP_Xbox_clip.bt new file mode 100644 index 00000000..a231a283 --- /dev/null +++ b/tools/quake3/Quake3Arena_BSP_Xbox_clip.bt @@ -0,0 +1,367 @@ +LittleEndian(); + +// char signature[4]; +// uint32 version; + +// typedef struct { +// uint32 offset; +// uint32 length; +// } lump ; + +// 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 ; + +FSeek( lumps.offShaders - OFF ); +Shader shader[lumps.nShaders]; + +typedef struct { + float normal[3]; + float dist; + int idk; +} Plane ; + +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 ; + +// 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 ; + +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 ; + +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 ; + +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 ; + +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 ; + +// 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; + +// 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 ; + +FSeek( lumps.offShaders - OFF ); +Shader shader[lumps.nShaders]; + +typedef struct { + float normal[3]; + float dist; + int idk; +} Plane ; + +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 ; + +// 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 ; + +// 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 ; +/* +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 ; + +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 ; + +// 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 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; +// } diff --git a/tools/quake3/q3map2/bspfile_ibsp.cpp b/tools/quake3/q3map2/bspfile_ibsp.cpp index 373328c7..73531914 100644 --- a/tools/quake3/q3map2/bspfile_ibsp.cpp +++ b/tools/quake3/q3map2/bspfile_ibsp.cpp @@ -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, "" ); + } ).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 ); + } + } + } +} diff --git a/tools/quake3/q3map2/bspfile_ibsp.h b/tools/quake3/q3map2/bspfile_ibsp.h index 0d289599..11e2f267 100644 --- a/tools/quake3/q3map2/bspfile_ibsp.h +++ b/tools/quake3/q3map2/bspfile_ibsp.h @@ -4,3 +4,5 @@ void LoadIBSPFile( const char *filename ); void WriteIBSPFile( const char *filename ); void LoadIBSPorRBSPFilePartially( const char *filename ); + +void LoadXboxFile( const char *filename ); diff --git a/tools/quake3/q3map2/convert_bsp.cpp b/tools/quake3/q3map2/convert_bsp.cpp index 39235f7f..c1ceba30 100644 --- a/tools/quake3/q3map2/convert_bsp.cpp +++ b/tools/quake3/q3map2/convert_bsp.cpp @@ -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" ); } diff --git a/tools/quake3/q3map2/convert_map.cpp b/tools/quake3/q3map2/convert_map.cpp index 5604339c..2fa8c3e2 100644 --- a/tools/quake3/q3map2/convert_map.cpp +++ b/tools/quake3/q3map2/convert_map.cpp @@ -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