From 1f76b1ddf76a9c6203d90bc1952f81728833a703 Mon Sep 17 00:00:00 2001 From: Anton Kovalev Date: Thu, 11 May 2023 11:30:40 +0200 Subject: [PATCH 1/3] Added support for lightmap pages (XBE) --- src/bsp.c | 118 ++++++++++++++++++++++++++++++++++++++--------------- src/vbsp.h | 35 ++++++++++++++-- 2 files changed, 117 insertions(+), 36 deletions(-) diff --git a/src/bsp.c b/src/bsp.c index 7d750d0..327c81b 100644 --- a/src/bsp.c +++ b/src/bsp.c @@ -32,6 +32,12 @@ struct AnyLump { uint32_t n; }; +/* + + VBSP_Lump_XBE_PakFile = 57, + VBSP_Lump_FaceHDR = 58, +*/ + struct Lumps { uint32_t version; #define LIST_LUMPS \ @@ -43,7 +49,7 @@ struct Lumps { BSPLUMP(Node, struct VBSPLumpNode, nodes); \ BSPLUMP(TexInfo, struct VBSPLumpTexInfo, texinfos); \ BSPLUMP(Face, struct VBSPLumpFace, faces); \ - BSPLUMP(LightMap, struct VBSPLumpLightMap, lightmaps); \ + BSPLUMP(LightMap, struct VBSPLightmapColor, lightmaps); \ \ BSPLUMP(Leaf, struct VBSPLumpLeaf, leaves); \ \ @@ -58,13 +64,17 @@ struct Lumps { BSPLUMP(DispVerts, struct VBSPLumpDispVert, dispverts); \ \ BSPLUMP(PakFile, uint8_t, pakfile); \ + BSPLUMP(XBE_PakFile, uint8_t, xbe_pakfile); \ \ BSPLUMP(TexDataStringData, char, texdatastringdata); \ BSPLUMP(TexDataStringTable, int32_t, texdatastringtable); \ \ + BSPLUMP(XBE_LightMapPages, struct VBSPLumpLightmapPage, lightmap_pages); \ + BSPLUMP(XBE_LightMapPagesInfos, struct VBSPLumpLightmapPageInfo, lightmap_pages_infos); \ + \ BSPLUMP(FaceHDR, struct VBSPLumpFace, faces_hdr); \ \ - BSPLUMP(LightMapHDR, struct VBSPLumpLightMap, lightmaps_hdr); \ + BSPLUMP(LightMapHDR, struct VBSPLightmapColor, lightmaps_hdr); \ #define BSPLUMP(name,type,field) struct{const type *p;uint32_t n;} field @@ -79,12 +89,14 @@ struct Face { int vertices; int indices; int width, height; - const struct VBSPLumpLightMap *samples; + int lm_page; + uint32_t lm_offset; + const struct VBSPLightmapColor* samples; const struct VBSPLumpTexInfo *texinfo; const struct VBSPLumpTexData *texdata; const struct VBSPLumpDispInfo *dispinfo; - int dispquadvtx[4]; // filled only when displaced int dispstartvtx; + int dispquadvtx[4]; // filled only when displaced const Material *material; /* filled as a result of atlas allocation */ @@ -134,7 +146,7 @@ static enum FacePreload bspFacePreloadMetadata(struct LoadModelContext *ctx, struct Face *face, unsigned index) { const struct Lumps * const lumps = ctx->lumps; #define FACE_CHECK(cond) \ - if (!(cond)) { PRINTF("F%u: check failed: (%s)", index, #cond); return FacePreload_Inconsistent; } + if (!(cond)) { __debugbreak(); PRINTF("F%u: check failed: (%s)", index, #cond); return FacePreload_Inconsistent; } FACE_CHECK(index < lumps->faces.n); const struct VBSPLumpFace * const vface = lumps->faces.p + index; @@ -191,14 +203,6 @@ static enum FacePreload bspFacePreloadMetadata(struct LoadModelContext *ctx, FACE_CHECK(vface->num_edges > 2); FACE_CHECK(vface->first_edge < lumps->surfedges.n && lumps->surfedges.n - vface->first_edge >= (unsigned)vface->num_edges); - FACE_CHECK(vface->lightmap_offset % sizeof(struct VBSPLumpLightMap) == 0); - - const int lm_width = vface->lightmap_size[0] + 1; - const int lm_height = vface->lightmap_size[1] + 1; - const unsigned lightmap_size = lm_width * lm_height; - const unsigned sample_offset = vface->lightmap_offset / sizeof(struct VBSPLumpLightMap); - FACE_CHECK(sample_offset < lumps->lightmaps.n && lumps->lightmaps.n - sample_offset >= lightmap_size); - const int32_t *surfedges = lumps->surfedges.p + vface->first_edge; unsigned int prev_end = 0xffffffffu; for (int i = 0; i < vface->num_edges; ++i) { @@ -237,11 +241,42 @@ static enum FacePreload bspFacePreloadMetadata(struct LoadModelContext *ctx, prev_end = vend; } - face->width = lm_width; - face->height = lm_height; - face->samples = lumps->lightmaps.p + sample_offset; - if (lm_width > ctx->lightmap.max_width) ctx->lightmap.max_width = lm_width; - if (lm_height > ctx->lightmap.max_height) ctx->lightmap.max_height = lm_height; + const int lm_width = vface->lightmap_size[0] + 1; + const int lm_height = vface->lightmap_size[1] + 1; + const unsigned lightmap_size = lm_width * lm_height; + + if (lumps->lightmap_pages.n > 0) { + /* palette XBE lightmaps */ + const int lm_page = lumps->lightmap_pages_infos.p[vface->lightmap_offset].page; + FACE_CHECK(lm_page < (int)lumps->lightmap_pages.n); + + const uint8_t cord_x = lumps->lightmap_pages_infos.p[vface->lightmap_offset].offset_s; + const uint8_t cord_y = lumps->lightmap_pages_infos.p[vface->lightmap_offset].offset_t; + FACE_CHECK(cord_x < VBSP_LightmapPage_Width); + FACE_CHECK(cord_y < VBSP_LightmapPage_Height); + const uint32_t lm_offset = cord_x + cord_y * VBSP_LightmapPage_Width; + + face->width = lm_width; + face->height = lm_height; + face->samples = NULL; + face->lm_page = lm_page; + face->lm_offset = lm_offset; + ctx->lightmap.max_width = VBSP_LightmapPage_Width; + ctx->lightmap.max_height = VBSP_LightmapPage_Height; + } else { + /* PC lightmaps */ + FACE_CHECK(vface->lightmap_offset % sizeof(struct VBSPLightmapColor) == 0); + + const uint32_t sample_offset = vface->lightmap_offset / sizeof(struct VBSPLightmapColor); + FACE_CHECK(sample_offset < lumps->lightmaps.n&& lumps->lightmaps.n - sample_offset >= lightmap_size); + face->width = lm_width; + face->height = lm_height; + face->samples = lumps->lightmaps.p; + face->lm_page = -1; + face->lm_offset = sample_offset; + if (lm_width > ctx->lightmap.max_width) ctx->lightmap.max_width = lm_width; + if (lm_height > ctx->lightmap.max_height) ctx->lightmap.max_height = lm_height; + } ctx->lightmap.pixels += lightmap_size; ctx->vertices += face->vertices; @@ -341,19 +376,35 @@ static enum BSPLoadResult bspLoadModelLightmaps(struct LoadModelContext *ctx) { const struct Face *const face = ctx->faces + i; ASSERT((unsigned)face->atlas_x + face->width <= atlas_context.width); ASSERT((unsigned)face->atlas_y + face->height <= atlas_context.height); - for (int y = 0; y < face->height; ++y) { - for (int x = 0; x < face->width; ++x) { - const struct VBSPLumpLightMap *const pixel = face->samples + x + (int)(y * face->width); - - const unsigned int - r = scaleLightmapColor(pixel->r, pixel->exponent), - g = scaleLightmapColor(pixel->g, pixel->exponent), - b = scaleLightmapColor(pixel->b, pixel->exponent); - - pixels[face->atlas_x + x + (face->atlas_y + y) * atlas_context.width] - = (uint16_t)(((r&0xf8) << 8) | ((g&0xfc) << 3) | (b >> 3)); - } /* for x */ - } /* for y */ + if (face->lm_page == -1) { + /* PC lightmaps */ + const struct VBSPLightmapColor* samples = face->samples + face->lm_offset; + for (int y = 0; y < face->height; ++y) { + for (int x = 0; x < face->width; ++x) { + const struct VBSPLightmapColor* const pixel = samples + x + (int)(y * face->width); + + const unsigned int + r = scaleLightmapColor(pixel->r, pixel->exponent), + g = scaleLightmapColor(pixel->g, pixel->exponent), + b = scaleLightmapColor(pixel->b, pixel->exponent); + + pixels[face->atlas_x + x + (face->atlas_y + y) * atlas_context.width] + = (uint16_t)(((r&0xf8) << 8) | ((g&0xfc) << 3) | (b >> 3)); + } /* for x */ + } /* for y */ + } else { + /* palette XBE lightmaps */ + const struct VBSPLumpLightmapPage* const page = &ctx->lumps->lightmap_pages.p[face->lm_page]; + for (int y = 0; y < face->height; ++y) { + for (int x = 0; x < face->width; ++x) { + const uint32_t offset = face->lm_offset + (x + y * face->width); + const struct VBSPLightmapPageColor* const pixel = &page->palette[page->data[offset]]; + + pixels[face->atlas_x + x + (face->atlas_y + y) * atlas_context.width] + = (uint16_t)(((pixel->r & 0xf8) << 8) | ((pixel->g & 0xfc) << 3) | (pixel->b >> 3)); + } + } + } } /* fot all visible faces */ RTextureUploadParams upload; @@ -370,7 +421,7 @@ static enum BSPLoadResult bspLoadModelLightmaps(struct LoadModelContext *ctx) { /* pixels buffer is not needed anymore */ stackFreeUpToPosition(ctx->tmp, pixels); - + return BSPLoadResult_Success; } @@ -1020,6 +1071,9 @@ enum BSPLoadResult bspLoadWorldspawn(BSPLoadModelContext context) { if (lumps.lightmaps.n == 0) { memcpy(&lumps.lightmaps, &lumps.lightmaps_hdr, sizeof(lumps.lightmaps)); + } + + if (lumps.faces.n == 0) { memcpy(&lumps.faces, &lumps.faces_hdr, sizeof(lumps.faces)); } diff --git a/src/vbsp.h b/src/vbsp.h index 94584d4..04f9af0 100644 --- a/src/vbsp.h +++ b/src/vbsp.h @@ -7,6 +7,11 @@ #pragma warning(disable:4214) #endif +enum { + VBSP_LightmapPage_Width = 256, + VBSP_LightmapPage_Height = 128 +}; + enum { VBSP_Lump_Entity = 0, VBSP_Lump_Plane = 1, @@ -35,14 +40,25 @@ enum { VBSP_Lump_TexDataStringData = 43, VBSP_Lump_TexDataStringTable = 44, + VBSP_Lump_XBE_LightMapPages = 51, + VBSP_Lump_XBE_LightMapPagesInfos = 52, + VBSP_Lump_LightMapHDR = 53, + VBSP_Lump_XBE_PakFile = 57, VBSP_Lump_FaceHDR = 58, VBSP_Lump_COUNT = 64 }; #pragma pack(1) +struct VBSPLightmapColor { + uint8_t r, g, b; + int8_t exponent; +}; +struct VBSPLightmapPageColor { + uint8_t b, g, r, a; +}; struct VBSPLumpHeader { uint32_t file_offset; uint32_t size; @@ -99,10 +115,6 @@ struct VBSPLumpFace { uint16_t first_primitive; uint32_t lightmap_smoothing_group; }; -struct VBSPLumpLightMap { - uint8_t r, g, b; - int8_t exponent; -}; struct VBSPLumpLeaf { uint32_t contents; uint16_t cluster; @@ -154,6 +166,17 @@ struct VBSPLumpDispInfo { struct VBSPLumpDispVert { float x, y, z, dist, alpha; }; +struct VBSPLumpLightmapPage { + uint8_t data[VBSP_LightmapPage_Width * VBSP_LightmapPage_Height]; + struct VBSPLightmapPageColor palette[256]; +}; +struct VBSPLumpLightmapPageInfo { + uint8_t page; + uint8_t offset_s; + uint8_t offset_t; + uint8_t padding; + struct VBSPLightmapColor color; +}; #pragma pack() enum VBSPSurfaceFlags { @@ -164,4 +187,8 @@ enum VBSPSurfaceFlags { VBSP_Surface_NoLight = 0x0400 }; +// pre-calculated mask for XBE lighmaps +#define LIGHTMAP_MASK_U 0x00005555 // w = 256 +#define LIGHTMAP_MASK_V 0x00002AAA // h = 128 + #endif /* ifndef VBSP_H__INCLUDED */ From cd624d977d926002688f3567d2a6526a5cf863ed Mon Sep 17 00:00:00 2001 From: Anton Kovalev Date: Thu, 11 May 2023 11:48:28 +0200 Subject: [PATCH 2/3] Code cleanups --- src/bsp.c | 8 +------- src/vbsp.h | 4 ---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/bsp.c b/src/bsp.c index 327c81b..1674f1c 100644 --- a/src/bsp.c +++ b/src/bsp.c @@ -32,12 +32,6 @@ struct AnyLump { uint32_t n; }; -/* - - VBSP_Lump_XBE_PakFile = 57, - VBSP_Lump_FaceHDR = 58, -*/ - struct Lumps { uint32_t version; #define LIST_LUMPS \ @@ -146,7 +140,7 @@ static enum FacePreload bspFacePreloadMetadata(struct LoadModelContext *ctx, struct Face *face, unsigned index) { const struct Lumps * const lumps = ctx->lumps; #define FACE_CHECK(cond) \ - if (!(cond)) { __debugbreak(); PRINTF("F%u: check failed: (%s)", index, #cond); return FacePreload_Inconsistent; } + if (!(cond)) { PRINTF("F%u: check failed: (%s)", index, #cond); return FacePreload_Inconsistent; } FACE_CHECK(index < lumps->faces.n); const struct VBSPLumpFace * const vface = lumps->faces.p + index; diff --git a/src/vbsp.h b/src/vbsp.h index 04f9af0..fb22d19 100644 --- a/src/vbsp.h +++ b/src/vbsp.h @@ -187,8 +187,4 @@ enum VBSPSurfaceFlags { VBSP_Surface_NoLight = 0x0400 }; -// pre-calculated mask for XBE lighmaps -#define LIGHTMAP_MASK_U 0x00005555 // w = 256 -#define LIGHTMAP_MASK_V 0x00002AAA // h = 128 - #endif /* ifndef VBSP_H__INCLUDED */ From 1acf5a297f16d42354d5601ad83f249a0076e295 Mon Sep 17 00:00:00 2001 From: Anton Kovalev Date: Thu, 11 May 2023 11:53:45 +0200 Subject: [PATCH 3/3] Added version check for lightmap pages --- src/bsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bsp.c b/src/bsp.c index 1674f1c..6068779 100644 --- a/src/bsp.c +++ b/src/bsp.c @@ -239,7 +239,7 @@ static enum FacePreload bspFacePreloadMetadata(struct LoadModelContext *ctx, const int lm_height = vface->lightmap_size[1] + 1; const unsigned lightmap_size = lm_width * lm_height; - if (lumps->lightmap_pages.n > 0) { + if (lumps->version == 19 && lumps->lightmap_pages.n > 0) { /* palette XBE lightmaps */ const int lm_page = lumps->lightmap_pages_infos.p[vface->lightmap_offset].page; FACE_CHECK(lm_page < (int)lumps->lightmap_pages.n);