@ -37,8 +37,10 @@ int process_textures(const world_t* world)
for ( int texNum = 0 ; texNum < world - > mipheader . numtex ; + + texNum )
for ( int texNum = 0 ; texNum < world - > mipheader . numtex ; + + texNum )
{
{
miptex_t * miptex = & world - > miptexes [ texNum ] ;
miptex_t * miptex = & world - > miptexes [ texNum ] ;
if ( miptex - > name [ 0 ] = = ' \0 ' ) // Weird edge case on N64START.bsp, corrupt data perhaps?
miptex - > width = miptex - > height = 0 ;
//printf("Texture %d (%dx%d): %.16s\n", texNum, miptex.width, miptex.height, miptex.name);
//printf("Texture %d (%dx%d): %.16s\n", texNum, miptex->width, miptex->height, miptex-> name);
// Shrink the larger textures, but keep smaller ones at their original size
// Shrink the larger textures, but keep smaller ones at their original size
int ps1mip = miptex - > width > 64 | | miptex - > height > 64 ? 1 : 0 ;
int ps1mip = miptex - > width > 64 | | miptex - > height > 64 ? 1 : 0 ;
@ -72,6 +74,8 @@ int process_textures(const world_t* world)
for ( int texNum = 0 ; texNum < world - > mipheader . numtex ; + + texNum )
for ( int texNum = 0 ; texNum < world - > mipheader . numtex ; + + texNum )
{
{
miptex_t * miptex = & world - > miptexes [ texNum ] ;
miptex_t * miptex = & world - > miptexes [ texNum ] ;
if ( miptex - > name [ 0 ] = = ' \0 ' ) // Weird edge case on N64START.bsp, corrupt data perhaps?
continue ;
char * outName = miptex - > name ;
char * outName = miptex - > name ;
if ( * outName = = ' * ' | | * outName = = ' + ' )
if ( * outName = = ' * ' | | * outName = = ' + ' )
@ -94,7 +98,7 @@ int process_textures(const world_t* world)
const auto & rectangle = rectangles [ texNum ] ;
const auto & rectangle = rectangles [ texNum ] ;
if ( miptex - > width > > mipLevel = = rectangle . w ) // This is the mip level we've previously decided we want for our PS1 atlas
if ( miptex - > width > > mipLevel = = rectangle . w ) // This is the mip level we've previously decided we want for our PS1 atlas
{
{
//printf("Writing texture %s mip %d to position: (%d, %d) w = %d, h = %d\n", miptex. name, mipLevel, rectangle.x, rectangle.y, rectangle.w, rectangle.h);
//printf("Writing texture %s mip %d to position: (%d, %d) w = %d, h = %d\n", miptex-> name, mipLevel, rectangle.x, rectangle.y, rectangle.w, rectangle.h);
for ( int y = 0 ; y < rectangle . h ; + + y )
for ( int y = 0 ; y < rectangle . h ; + + y )
{
{
memcpy_s ( atlas + ( ( rectangle . y + y ) * result_size . w + rectangle . x ) , rectangle . w * sizeof ( unsigned char ) , texBytes + ( y * rectangle . w ) , rectangle . w * sizeof ( unsigned char ) ) ;
memcpy_s ( atlas + ( ( rectangle . y + y ) * result_size . w + rectangle . x ) , rectangle . w * sizeof ( unsigned char ) , texBytes + ( y * rectangle . w ) , rectangle . w * sizeof ( unsigned char ) ) ;
@ -146,6 +150,20 @@ typedef struct
unsigned short index ;
unsigned short index ;
} vertexref_t ;
} vertexref_t ;
// Determines a floating origin for the given leaf
static void leaf_zone ( const dleaf_t * leaf , short zone [ 3 ] )
{
const unsigned short mask = 0xFE00 ; // Zero out the 9 least significant bits
short midX = ( leaf - > bound . min [ 0 ] + leaf - > bound . max [ 0 ] ) / 2 ;
short midY = ( leaf - > bound . min [ 1 ] + leaf - > bound . max [ 1 ] ) / 2 ;
short midZ = ( leaf - > bound . min [ 2 ] + leaf - > bound . max [ 2 ] ) / 2 ;
zone [ 0 ] = midX & mask ;
zone [ 1 ] = midY & mask ;
zone [ 2 ] = midZ & mask ;
}
int process_faces ( const world_t * world )
int process_faces ( const world_t * world )
{
{
// Write some data to a file
// Write some data to a file
@ -158,21 +176,21 @@ int process_faces(const world_t* world)
fwrite ( & outHeader , sizeof ( ps1bsp_header_t ) , 1 , fbsp ) ;
fwrite ( & outHeader , sizeof ( ps1bsp_header_t ) , 1 , fbsp ) ;
// TODO: convert vertices and group them by material properties (texture, lightmap) and floating origin zone (based on leaf data), duplicate where necessary
// TODO: convert vertices and group them by material properties (texture, lightmap) and floating origin zone (based on leaf data), duplicate where necessary
// Organize vertex indices so we can shuffle them around and duplicate them, while keeping track of which vertex is where
std : : unordered_map < vertex_t * , vertexref_t > vertexRefs ;
for ( unsigned short i = 0 ; i < world - > header . vertices . size / sizeof ( vertex_t ) ; + + i )
short zone [ 3 ] ;
for ( int leafIdx = 0 ; leafIdx < world - > numLeaves ; + + leafIdx )
{
{
vertex_t * v = & world - > vertices [ i ] ;
vertexRefs [ v ] = vertexref_t { v , i } ;
dleaf_t * leaf = & world - > leaves [ leafIdx ] ;
leaf_zone ( leaf , zone ) ;
//printf("Leaf %d zone (%d, %d, %d) %d face(s)\n", leafIdx, zone[0], zone[1], zone[2], leaf->lface_num);
}
}
// Write vertex data to a file (no vertex splitting yet)
// Write vertex data to a file (no vertex splitting yet)
for ( unsigned short i = 0 ; i < world - > header . vertices . size / sizeof ( vertex_t ) ; + + i )
for ( unsigned short i = 0 ; i < world - > numVertices ; + + i )
{
{
// TODO: we should respect the ordering from vertexRef->index here but meh, problem for later
// TODO: we should respect the ordering from vertexRef->index here but meh, problem for later
vertex_t * inVertex = & world - > vertices [ i ] ;
vertex_t * inVertex = & world - > vertices [ i ] ;
ps1bsp_vertex_t outVertex = { 0 } ;
ps1bsp_vertex_t outVertex = { 0 } ;
// Ensure we don't overflow 16-bit short values. Most Quake maps will stay within these bounds so it *should* be fine (for now).
if ( inVertex - > X > - 8192 & & inVertex - > X < 8192 & & inVertex - > Y > - 8192 & & inVertex - > Y < 8192 & & inVertex - > Z > - 8192 & & inVertex - > Z < 8192 )
if ( inVertex - > X > - 8192 & & inVertex - > X < 8192 & & inVertex - > Y > - 8192 & & inVertex - > Y < 8192 & & inVertex - > Z > - 8192 & & inVertex - > Z < 8192 )
{
{
outVertex . x = ( short ) ( inVertex - > X * 4 ) ;
outVertex . x = ( short ) ( inVertex - > X * 4 ) ;
@ -184,39 +202,66 @@ int process_faces(const world_t* world)
fwrite ( & outVertex , sizeof ( ps1bsp_vertex_t ) , 1 , fbsp ) ;
fwrite ( & outVertex , sizeof ( ps1bsp_vertex_t ) , 1 , fbsp ) ;
}
}
outHeader . numVertices = ( unsigned short ) ( world - > header . vertices . size / sizeof ( vertex_t ) ) ;
std : : vector < ps1bsp_triangle_t > outTriangles ;
std : : vector < ps1bsp_face_t > outFaces ;
std : : vector < vertexref_t * > faceVerts ;
std : : vector < unsigned short > faceVertIndice s ;
for ( int faceIdx = 0 ; faceIdx < world - > numFaces ; + + faceIdx )
for ( int faceIdx = 0 ; faceIdx < world - > numFaces ; + + faceIdx )
{
{
face_t * face = & world - > faces [ faceIdx ] ;
face_t * face = & world - > faces [ faceIdx ] ;
// Traverse the list of face edges to collect all of the face's vertices
for ( int edgeListIdx = 0 ; edgeListIdx < face - > ledge_num ; + + edgeListIdx )
for ( int edgeListIdx = 0 ; edgeListIdx < face - > ledge_num ; + + edgeListIdx )
{
{
shor t edgeIdx = world - > edgeList [ face - > ledge_id + edgeListIdx ] ;
in t edgeIdx = world - > edgeList [ face - > ledge_id + edgeListIdx ] ;
int vertIndex = edgeIdx > 0 ?
uns ig ned shor t vertIndex = edgeIdx > 0 ?
world - > edges [ edgeIdx ] . vertex0 :
world - > edges [ edgeIdx ] . vertex0 :
world - > edges [ - edgeIdx ] . vertex1 ;
world - > edges [ - edgeIdx ] . vertex1 ;
vertex_t * v = & world - > vertices [ vertIndex ] ;
faceVerts . push_back ( & vertexRefs [ v ] ) ;
faceVertIndices . push_back ( vertIndex ) ;
}
}
printf ( " Face %d: %d vertices \n " , faceIdx , faceVerts . size ( ) ) ;
ps1bsp_face_t outFace = { 0 } ;
outFace . firstTriangleId = outTriangles . size ( ) ;
//printf("Face %d: %d vertices\n", faceIdx, faceVerts.size());
// Triangulate face into polygons (triangle fan, the naive method)
// Triangulate face into polygons (triangle fan, the naive method)
// TODO better method: generate a quad strip topology
ps1bsp_triangle_t outTriangle ;
outTriangle . vertex0 = faceVertIndices [ 0 ] ;
for ( int faceVertIdx = 1 ; faceVertIdx < faceVertIndices . size ( ) - 1 ; + + faceVertIdx )
{
outTriangle . vertex1 = faceVertIndices [ faceVertIdx ] ;
outTriangle . vertex2 = faceVertIndices [ faceVertIdx + 1 ] ;
outTriangles . push_back ( outTriangle ) ;
}
// Write polygon and face data to a file
outFace . numTriangles = outTriangles . size ( ) - outFace . firstTriangleId ;
outFaces . push_back ( outFace ) ;
faceVerts . clear ( ) ;
faceVertIndice s . clear ( ) ;
}
}
// Write triangle and face data to file
fwrite ( outTriangles . data ( ) , sizeof ( ps1bsp_triangle_t ) , outTriangles . size ( ) , fbsp ) ;
fwrite ( outFaces . data ( ) , sizeof ( ps1bsp_face_t ) , outFaces . size ( ) , fbsp ) ;
// Update header information
outHeader . numVertices = world - > numVertices ;
outHeader . numTriangles = outTriangles . size ( ) ;
outHeader . numFaces = outFaces . size ( ) ;
// Write final header
// Write final header
fseek ( fbsp , 0 , SEEK_SET ) ;
fseek ( fbsp , 0 , SEEK_SET ) ;
fwrite ( & outHeader , sizeof ( ps1bsp_header_t ) , 1 , fbsp ) ;
fwrite ( & outHeader , sizeof ( ps1bsp_header_t ) , 1 , fbsp ) ;
fclose ( fbsp ) ;
fclose ( fbsp ) ;
printf ( " PS1BSP: wrote %d vertices, %d triangles, %d faces \n " , outHeader . numVertices , outHeader . numTriangles , outHeader . numFaces ) ;
return 1 ;
return 1 ;
}
}
@ -317,6 +362,15 @@ int load_bsp(const char* bspname, world_t* world)
world - > textures [ texNum * numMipLevels + mipLevel ] = texBytes ;
world - > textures [ texNum * numMipLevels + mipLevel ] = texBytes ;
}
}
}
}
// Load planes
world - > numPlanes = header - > planes . size / sizeof ( plane_t ) ;
world - > planes = ( plane_t * ) malloc ( header - > planes . size ) ;
if ( world - > planes = = NULL )
return 0 ;
fseek ( f , header - > planes . offset , SEEK_SET ) ;
fread ( world - > planes , sizeof ( plane_t ) , world - > numPlanes , f ) ;
// Load vertices
// Load vertices
world - > numVertices = header - > vertices . size / sizeof ( vertex_t ) ;
world - > numVertices = header - > vertices . size / sizeof ( vertex_t ) ;
@ -336,13 +390,13 @@ int load_bsp(const char* bspname, world_t* world)
fseek ( f , header - > edges . offset , SEEK_SET ) ;
fseek ( f , header - > edges . offset , SEEK_SET ) ;
fread ( world - > edges , sizeof ( edge_t ) , world - > numEdges , f ) ;
fread ( world - > edges , sizeof ( edge_t ) , world - > numEdges , f ) ;
world - > edgeListLength = header - > ledges . size / sizeof ( uns ig ned shor t) ;
world - > edgeList = ( uns ig ned shor t* ) malloc ( header - > ledges . size ) ;
world - > edgeListLength = header - > ledges . size / sizeof ( int ) ;
world - > edgeList = ( int * ) malloc ( header - > ledges . size ) ;
if ( world - > edgeList = = NULL )
if ( world - > edgeList = = NULL )
return 0 ;
return 0 ;
fseek ( f , header - > ledges . offset , SEEK_SET ) ;
fseek ( f , header - > ledges . offset , SEEK_SET ) ;
fread ( world - > edgeList , sizeof ( uns ig ned shor t) , world - > edgeListLength , f ) ;
fread ( world - > edgeList , sizeof ( int ) , world - > edgeListLength , f ) ;
// Load faces
// Load faces
world - > numFaces = header - > faces . size / sizeof ( face_t ) ;
world - > numFaces = header - > faces . size / sizeof ( face_t ) ;
@ -358,9 +412,18 @@ int load_bsp(const char* bspname, world_t* world)
if ( world - > faceList = = NULL )
if ( world - > faceList = = NULL )
return 0 ;
return 0 ;
// Load visibility list
fseek ( f , header - > lface . offset , SEEK_SET ) ;
fseek ( f , header - > lface . offset , SEEK_SET ) ;
fread ( world - > faceList , sizeof ( unsigned short ) , world - > faceListLength , f ) ;
fread ( world - > faceList , sizeof ( unsigned short ) , world - > faceListLength , f ) ;
world - > visListLength = header - > visilist . size / sizeof ( unsigned char ) ;
world - > visList = ( unsigned char * ) malloc ( header - > visilist . size ) ;
if ( world - > visList = = NULL )
return 0 ;
fseek ( f , header - > visilist . offset , SEEK_SET ) ;
fread ( world - > visList , sizeof ( unsigned char ) , world - > visListLength , f ) ;
// Load nodes
// Load nodes
world - > numNodes = header - > nodes . size / sizeof ( node_t ) ;
world - > numNodes = header - > nodes . size / sizeof ( node_t ) ;
world - > nodes = ( node_t * ) malloc ( header - > nodes . size ) ;
world - > nodes = ( node_t * ) malloc ( header - > nodes . size ) ;
@ -387,12 +450,14 @@ void free_bsp(world_t* world)
{
{
free ( world - > leaves ) ;
free ( world - > leaves ) ;
free ( world - > nodes ) ;
free ( world - > nodes ) ;
free ( world - > visList ) ;
free ( world - > faces ) ;
free ( world - > faces ) ;
free ( world - > faceList ) ;
free ( world - > faceList ) ;
free ( world - > edges ) ;
free ( world - > edges ) ;
free ( world - > edgeList ) ;
free ( world - > edgeList ) ;
free ( world - > vertices ) ;
free ( world - > vertices ) ;
free ( world - > planes ) ;
for ( int i = 0 ; i < world - > mipheader . numtex ; + + i )
for ( int i = 0 ; i < world - > mipheader . numtex ; + + i )
{
{