#ifndef __PS1BSP_H__ #define __PS1BSP_H__ #ifdef __cplusplus extern "C" { #endif /* Probable rendering process: - Determine visible leaves based on PVS and frustum culling, the usual. - Chain together faces/polygons to be drawn. Possibly grouped by texture ID? Texture chaining might improve performance by making better use of texture cache, but we'll still be separating polygons based on depth anyway, so the advantage is questionable. Texture chaining should probably be the last optimization we try. - Tessellate polygons close to the camera by recursively cutting edges in two, up to X times based on camera distance/screen size. Possibly GTE can aid with averaging coordinates? => look at GPF/GPL (general purpose interpolation) - Collect all vertices that need to be transformed, put them through GTE, update lighting values if needed, and cache the results. (It may not be worth it to collect and precalculate vertices, as keeping track of all the administration also comes at a considerable cost.) - Draw all the (tessellated) polygons using the precalculated vertex positions. Use GTE to calculate average depth and order polygons. Note: we may not have to calculate average depth for BSP polygons, as the leafs already provide an ordering, and leafs are convex so there is no need to sort the polygons within. We do however need some kind of depth value per leaf to insert alias models at the correct positions in the ordering table. */ typedef struct { unsigned short numVertices; unsigned short numTriangles; unsigned short numFaces; } ps1bsp_header_t; typedef struct { unsigned char w, h; // These may be necessary for scaling UVs, especially since we use a mix of mip0 and mip1 textures int tpage; // Texture page in PS1 VRAM (precalculated when generating the texture atlas) short uoffs, voffs; // Texture coordinate offset within the texture page unsigned short nextframe; // If non-zero, the texture is animated and this points to the next texture in the sequence } ps1bsp_texture_t; // This matches the SVECTOR data type, using the extra padding to store vertex color data. // The full range and precision required cannot be stored in just shorts, so we make use of a floating origin stored in the BSP leafs. // With this the higher-order bits of each vertex position are calculated into the model-view matrix, giving good precision for polygons near the camera. typedef struct { short x; short y; short z; unsigned char baseLight, finalLight; // Used for gouraud shading based on static lightmap data // Sampled color value from the face texture, for untextured gouraud shaded drawing unsigned char a : 1; // 0 = opaque, 1 = semi-transparent unsigned char r : 5; unsigned char g : 5; unsigned char b : 5; } ps1bsp_vertex_t; // Instead of edges as in the original BSP format, we store triangles for easy consumption by the PS1 // Note: it may actually be more efficient to render quads for faces with 4+ vertices typedef struct { unsigned short vertex0; unsigned short vertex1; unsigned short vertex2; } ps1bsp_triangle_t; typedef struct { unsigned short firstTriangleId; // TODO: could also just do first-index, num-indices here. No real need for a triangle_t struct. unsigned short numTriangles; unsigned short firstQuadId; // For if/when we decide to add quads to the mix unsigned short numQuads; } ps1bsp_face_t; // Pre-parsed and encoded entity data (this runs the risk of becoming too bloated) typedef struct { unsigned short classtype; // Hash of the original classname short angle[3]; // Can store both mangle (all axes) and just angle (Z-axis rotation only) int origin[3]; // In 12-bit fixed point coordinates unsigned int spawnflags; unsigned short messageId; // Index into a pool of pre-defined messages } ps1bsp_entity_t; typedef struct { unsigned short length; char message[]; } ps1bsp_message_t; typedef struct { // TODO: add floating origin position, so face vertices can be moved relative to the camera position } ps1bsp_leaf_t; #ifdef __cplusplus } #endif #endif // __PS1BSP_H__