diff --git a/src/common/header/files.h b/src/common/header/files.h index b1afaab..2feb1b0 100644 --- a/src/common/header/files.h +++ b/src/common/header/files.h @@ -333,9 +333,10 @@ typedef struct m32tex_s /* .BSP file format */ #define IDBSPHEADER (('P' << 24) + ('S' << 16) + ('B' << 8) + 'I') /* little-endian "IBSP" */ +#define BSPXHEADER (('X' << 24) + ('P' << 16) + ('S' << 8) + 'B') /* little-endian "BSPX" */ #define BSPVERSION 38 -/* upper design bounds: leaffaces, leafbrushes, planes, and +/* upper design bounds: leaffaces, leafbrushes, planes, and * verts are still bounded by 16 bit short limits */ #define MAX_MAP_MODELS 1024 #define MAX_MAP_BRUSHES 8192 @@ -399,6 +400,17 @@ typedef struct lump_t lumps[HEADER_LUMPS]; } dheader_t; +typedef struct bspx_header_s { + int ident; // 'BSPX' + int numlumps; +} bspx_header_t; + +typedef struct { + char lumpname[24]; + int fileofs; + int filelen; +} bspx_lump_t; + typedef struct { float mins[3], maxs[3]; @@ -493,12 +505,12 @@ typedef struct texinfo_s { float vecs[2][4]; /* [s/t][xyz offset] */ int flags; /* miptex flags + overrides light emission, etc */ - int value; + int value; char texture[32]; /* texture name (textures*.wal) */ int nexttexinfo; /* for animations, -1 = end of chain */ } texinfo_t; -/* note that edge 0 is never used, because negative edge +/* note that edge 0 is never used, because negative edge nums are used for counterclockwise use of the edge in a face */ typedef struct @@ -521,6 +533,13 @@ typedef struct int lightofs; /* start of [numstyles*surfsize] samples */ } dface_t; +typedef struct { + unsigned short lmwidth; + unsigned short lmheight; + int lightofs; + float vecs[2][4]; +} dlminfo_t; + typedef struct { int contents; /* OR of all brushes (not needed?) */ @@ -554,8 +573,8 @@ typedef struct #define ANGLE_UP -1 #define ANGLE_DOWN -2 -/* the visibility lump consists of a header with a count, then - * byte offsets for the PVS and PHS of each cluster, then the raw +/* the visibility lump consists of a header with a count, then + * byte offsets for the PVS and PHS of each cluster, then the raw * compressed bit vectors */ #define DVIS_PVS 0 #define DVIS_PHS 1 diff --git a/src/vk/header/model.h b/src/vk/header/model.h index 533331b..9f49ea4 100644 --- a/src/vk/header/model.h +++ b/src/vk/header/model.h @@ -43,6 +43,7 @@ BRUSH MODELS // #define VERTEXSIZE 7 +#define DEFAULT_LMSHIFT 4 typedef struct vkpoly_s { @@ -66,6 +67,8 @@ typedef struct msurface_s short texturemins[2]; short extents[2]; + short lmshift; + int light_s, light_t; // gl lightmap coordinates int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps @@ -75,7 +78,11 @@ typedef struct msurface_s mtexinfo_t *texinfo; -// lighting info + /* decoupled lm */ + float lmvecs[2][4]; + float lmvlen[2]; + + /* lighting info */ int dlightframe; int dlightbits; diff --git a/src/vk/vk_light.c b/src/vk/vk_light.c index 30e9671..390cb5c 100644 --- a/src/vk/vk_light.c +++ b/src/vk/vk_light.c @@ -215,9 +215,9 @@ RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end, vec3_t pointcolor) } frac = front / (front-back); - mid[0] = start[0] + (end[0] - start[0])*frac; - mid[1] = start[1] + (end[1] - start[1])*frac; - mid[2] = start[2] + (end[2] - start[2])*frac; + mid[0] = start[0] + (end[0] - start[0]) * frac; + mid[1] = start[1] + (end[1] - start[1]) * frac; + mid[2] = start[2] + (end[2] - start[2]) * frac; /* go down front side */ r = RecursiveLightPoint(node->children[side], start, mid, pointcolor); @@ -262,13 +262,13 @@ RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end, vec3_t pointcolor) return 0; } - ds >>= 4; - dt >>= 4; + ds >>= surf->lmshift; + dt >>= surf->lmshift; lightmap = surf->samples; VectorCopy(vec3_origin, pointcolor); - lightmap += 3 * (dt * ((surf->extents[0] >> 4) + 1) + ds); + lightmap += 3 * (dt * ((surf->extents[0] >> surf->lmshift) + 1) + ds); for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { @@ -276,14 +276,14 @@ RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end, vec3_t pointcolor) for (j = 0; j < 3; j++) { - scale[j] = r_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[j]; + scale[j] = r_modulate->value * r_newrefdef.lightstyles[surf->styles[maps]].rgb[j]; } pointcolor[0] += lightmap[0] * scale[0] * (1.0/255); pointcolor[1] += lightmap[1] * scale[1] * (1.0/255); pointcolor[2] += lightmap[2] * scale[2] * (1.0/255); - lightmap += 3 * ((surf->extents[0] >> 4) + 1) * - ((surf->extents[1] >> 4) + 1); + lightmap += 3 * ((surf->extents[0] >> surf->lmshift) + 1) * + ((surf->extents[1] >> surf->lmshift) + 1); } return 1; @@ -367,14 +367,12 @@ R_AddDynamicLights(msurface_t *surf) int s, t; int i; int smax, tmax; - mtexinfo_t *tex; dlight_t *dl; float *plightdest; float fsacc, ftacc; - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; - tex = surf->texinfo; + smax = (surf->extents[0] >> surf->lmshift) + 1; + tmax = (surf->extents[1] >> surf->lmshift) + 1; for (lnum=0 ; lnumplane->normal[i]*fdist; } - local[0] = DotProduct(impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0]; - local[1] = DotProduct(impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1]; + local[0] = DotProduct (impact, surf->lmvecs[0]) + surf->lmvecs[0][3] - surf->texturemins[0]; + local[1] = DotProduct (impact, surf->lmvecs[1]) + surf->lmvecs[1][3] - surf->texturemins[1]; plightdest = s_blocklights; - for (t = 0, ftacc = 0 ; tlmshift)) { td = local[1] - ftacc; - if ( td < 0 ) + if (td < 0) td = -td; - for ( s=0, fsacc = 0 ; slmvlen[1]; + + for ( s=0, fsacc = 0 ; slmshift), plightdest += 3) { sd = Q_ftol( local[0] - fsacc ); if ( sd < 0 ) sd = -sd; + sd *= surf->lmvlen[0]; + if (sd > td) fdist = sd + (td>>1); else @@ -479,8 +481,8 @@ R_BuildLightMap(msurface_t *surf, byte *dest, int stride) ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface"); } - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; + smax = (surf->extents[0] >> surf->lmshift) + 1; + tmax = (surf->extents[1] >> surf->lmshift) + 1; size = smax * tmax; if (!s_blocklights || (s_blocklights + (size * 3) >= s_blocklights_max)) diff --git a/src/vk/vk_mesh.c b/src/vk/vk_mesh.c index 4bcd68b..41d98e2 100644 --- a/src/vk/vk_mesh.c +++ b/src/vk/vk_mesh.c @@ -356,7 +356,8 @@ Vk_DrawAliasFrameLerpCommands (entity_t *currententity, int *order, int *order_e } else { - meshUbo.textured = 1; + /* Do not apply texture for lighmap debug case */ + meshUbo.textured = r_lightmap->value ? 0 : 1; do { int vertIdx = vertCounts[pipelineIdx]; diff --git a/src/vk/vk_model.c b/src/vk/vk_model.c index f77be30..c2e79a8 100644 --- a/src/vk/vk_model.c +++ b/src/vk/vk_model.c @@ -375,17 +375,154 @@ calcTexinfoAndFacesSize(const lump_t *fl, const byte *mod_base, const lump_t *tl return ret; } +// Extension to support lightmaps that aren't tied to texture scale. +static int +Mod_LoadDecoupledLM(const dlminfo_t* lminfos, int surfnum, msurface_t *out) +{ + const dlminfo_t *lminfo; + unsigned short lmwidth, lmheight; + + if (lminfos == NULL) { + return -1; + } + + lminfo = lminfos + surfnum; + + lmwidth = LittleShort(lminfo->lmwidth); + lmheight = LittleShort(lminfo->lmheight); + + if (lmwidth <= 0 || lmheight <= 0) { + return -1; + } + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 4; j++) { + out->lmvecs[i][j] = LittleFloat(lminfo->vecs[i][j]); + } + } + + out->extents[0] = (short)(lmwidth - 1); + out->extents[1] = (short)(lmheight - 1); + out->lmshift = 0; + out->texturemins[0] = 0; + out->texturemins[1] = 0; + + float v0 = VectorLength(out->lmvecs[0]); + out->lmvlen[0] = v0 > 0.0f ? 1.0f / v0 : 0.0f; + + float v1 = VectorLength(out->lmvecs[1]); + out->lmvlen[1] = v1 > 0.0f ? 1.0f / v1 : 0.0f; + + return LittleLong(lminfo->lightofs); +} + +const void * +Mod_BSPX_FindLump(bspx_header_t* bspx_header, char* lumpname, int* plumpsize, const byte* mod_base) +{ + int i; + bspx_lump_t* lump; + + if (!bspx_header) { + return NULL; + } + + lump = (bspx_lump_t*)(bspx_header + 1); + for (i = 0; i < bspx_header->numlumps; i++, lump++) { + if (!strcmp(lump->lumpname, lumpname)) { + if (plumpsize) { + *plumpsize = lump->filelen; + } + return mod_base + lump->fileofs; + } + } + + return NULL; +} + +bspx_header_t * +Mod_LoadBSPX(int filesize, byte* mod_base) +{ + dheader_t* header; + bspx_header_t* xheader; + bspx_lump_t* lump; + int i; + int xofs; + + // find end of last lump + header = (dheader_t*)mod_base; + xofs = 0; + for (i = 0; i < HEADER_LUMPS; i++) { + xofs = max(xofs, + ROUNDUP(header->lumps[i].fileofs + header->lumps[i].filelen, sizeof(int))); + } + + if (xofs + sizeof(bspx_header_t) > filesize) { + return NULL; + } + + xheader = (bspx_header_t*)(mod_base + xofs); + if (LittleLong(xheader->ident) != BSPXHEADER) + { + R_Printf(PRINT_ALL, "%s: Incorrect header ident.\n", + __func__, xheader->ident, BSPXHEADER); + return NULL; + } + + xheader->numlumps = LittleLong(xheader->numlumps); + + if (xheader->numlumps < 0 || xofs + sizeof(bspx_header_t) + xheader->numlumps * sizeof(bspx_lump_t) > filesize) { + return NULL; + } + + // byte-swap and check sanity + lump = (bspx_lump_t*)(xheader + 1); // lumps immediately follow the header + for (i = 0; i < xheader->numlumps; i++, lump++) { + lump->lumpname[sizeof(lump->lumpname) - 1] = '\0'; // make sure it ends with zero + lump->fileofs = LittleLong(lump->fileofs); + lump->filelen = LittleLong(lump->filelen); + if (lump->fileofs < 0 || lump->filelen < 0 || (unsigned)(lump->fileofs + lump->filelen) >(unsigned)filesize) { + return NULL; + } + } + + // success + return xheader; +} + +static void +SetSurfaceLighting(model_t* loadmodel, msurface_t* out, byte* styles, int lightofs) +{ + int i; + + /* lighting info */ + for (i = 0; i < MAXLIGHTMAPS; i++) + { + out->styles[i] = styles[i]; + } + + i = LittleLong(lightofs); + if (i == -1 || loadmodel->lightdata == NULL) + { + out->samples = NULL; + } + else + { + out->samples = loadmodel->lightdata + i; + } +} + /* ================= Mod_LoadFaces ================= */ static void -Mod_LoadFaces (model_t *loadmodel, const byte *mod_base, const lump_t *l) +Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, bspx_header_t *bspx_header) { - dface_t *in; + int i, count, surfnum, lminfosize, lightofs; + const dlminfo_t *lminfos; msurface_t *out; - int i, count, surfnum; + dface_t *in; in = (void *)(mod_base + l->fileofs); @@ -401,6 +538,13 @@ Mod_LoadFaces (model_t *loadmodel, const byte *mod_base, const lump_t *l) loadmodel->surfaces = out; loadmodel->numsurfaces = count; + lminfos = Mod_BSPX_FindLump(bspx_header, "DECOUPLED_LM", &lminfosize, mod_base); + if (lminfos != NULL && lminfosize / sizeof(dlminfo_t) != loadmodel->numsurfaces) { + R_Printf(PRINT_ALL, "%s: [%s] decoupled_lm size %ld does not match surface count %d\n", + __func__, loadmodel->name, lminfosize / sizeof(dlminfo_t), loadmodel->numsurfaces); + lminfos = NULL; + } + Vk_BeginBuildingLightmaps(loadmodel); for (surfnum = 0; surfnum < count; surfnum++, in++, out++) @@ -444,24 +588,19 @@ Mod_LoadFaces (model_t *loadmodel, const byte *mod_base, const lump_t *l) out->texinfo = loadmodel->texinfo + ti; - CalcSurfaceExtents(loadmodel, out); + lightofs = Mod_LoadDecoupledLM(lminfos, surfnum, out); + if (lightofs < 0) { + memcpy(out->lmvecs, out->texinfo->vecs, sizeof(out->lmvecs)); + out->lmshift = DEFAULT_LMSHIFT; + out->lmvlen[0] = 1.0f; + out->lmvlen[1] = 1.0f; - /* lighting info */ - for (i = 0; i < MAXLIGHTMAPS; i++) - { - out->styles[i] = in->styles[i]; + CalcSurfaceExtents(loadmodel, out); + + lightofs = in->lightofs; } - i = LittleLong(in->lightofs); - - if (i == -1) - { - out->samples = NULL; - } - else - { - out->samples = loadmodel->lightdata + i; - } + SetSurfaceLighting(loadmodel, out, in->styles, lightofs); /* set the drawing flags */ if (out->texinfo->flags & SURF_WARP) @@ -635,9 +774,10 @@ Mod_LoadBrushModel static void Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) { - int i; - dheader_t *header; + bspx_header_t* bspx_header; byte *mod_base; + dheader_t *header; + int i; header = (dheader_t *)buffer; @@ -677,6 +817,10 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) mod->extradata = Hunk_Begin(hunkSize); mod->type = mod_brush; + + /* check for BSPX extensions */ + bspx_header = Mod_LoadBSPX(modfilelen, (byte*)header); + /* load into heap */ Mod_LoadVertexes(mod->name, &mod->vertexes, &mod->numvertexes, mod_base, &header->lumps[LUMP_VERTEXES], 0); @@ -685,14 +829,14 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen) Mod_LoadSurfedges(mod->name, &mod->surfedges, &mod->numsurfedges, mod_base, &header->lumps[LUMP_SURFEDGES], 0); Mod_LoadLighting(&mod->lightdata, mod_base, &header->lumps[LUMP_LIGHTING]); - Mod_LoadPlanes (mod->name, &mod->planes, &mod->numplanes, + Mod_LoadPlanes(mod->name, &mod->planes, &mod->numplanes, mod_base, &header->lumps[LUMP_PLANES], 0); Mod_LoadTexinfo(mod->name, &mod->texinfo, &mod->numtexinfo, mod_base, &header->lumps[LUMP_TEXINFO], (findimage_t)Vk_FindImage, r_notexture, 0); - Mod_LoadFaces(mod, mod_base, &header->lumps[LUMP_FACES]); + Mod_LoadFaces(mod, mod_base, &header->lumps[LUMP_FACES], bspx_header); Mod_LoadMarksurfaces(mod, mod_base, &header->lumps[LUMP_LEAFFACES]); - Mod_LoadVisibility (&mod->vis, mod_base, &header->lumps[LUMP_VISIBILITY]); + Mod_LoadVisibility(&mod->vis, mod_base, &header->lumps[LUMP_VISIBILITY]); Mod_LoadLeafs(mod, mod_base, &header->lumps[LUMP_LEAFS]); Mod_LoadNodes(mod->name, mod->planes, mod->numplanes, mod->leafs, mod->numleafs, &mod->nodes, &mod->numnodes, mod_base, diff --git a/src/vk/vk_rsurf.c b/src/vk/vk_rsurf.c index 0b0f663..a452788 100644 --- a/src/vk/vk_rsurf.c +++ b/src/vk/vk_rsurf.c @@ -303,8 +303,8 @@ static void R_RenderBrushPoly (msurface_t *fa, float *modelMatrix, float alpha, unsigned temp[34 * 34]; int smax, tmax; - smax = (fa->extents[0] >> 4) + 1; - tmax = (fa->extents[1] >> 4) + 1; + smax = (fa->extents[0] >> fa->lmshift) + 1; + tmax = (fa->extents[1] >> fa->lmshift) + 1; R_BuildLightMap(fa, (void *)temp, smax * 4); R_SetCacheState(fa); @@ -477,8 +477,8 @@ static void Vk_RenderLightmappedPoly( msurface_t *surf, float *modelMatrix, floa unsigned temp[128 * 128]; int smax, tmax; - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; + smax = (surf->extents[0] >> surf->lmshift) + 1; + tmax = (surf->extents[1] >> surf->lmshift) + 1; R_BuildLightMap(surf, (void *)temp, smax * 4); @@ -1131,10 +1131,11 @@ void Vk_BuildPolygonFromSurface(msurface_t *fa, model_t *currentmodel) lnumverts = fa->numedges; VectorClear (total); + // // draw texture // - poly = Hunk_Alloc (sizeof(vkpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); + poly = Hunk_Alloc (sizeof(vkpoly_t) + (lnumverts-4) * VERTEXSIZE * sizeof(float)); poly->next = fa->polys; poly->flags = fa->flags; fa->polys = poly; @@ -1172,17 +1173,17 @@ void Vk_BuildPolygonFromSurface(msurface_t *fa, model_t *currentmodel) // // lightmap texture coordinates // - s = DotProduct(vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s = DotProduct(vec, fa->lmvecs[0]) + fa->lmvecs[0][3]; s -= fa->texturemins[0]; - s += fa->light_s*16; - s += 8; - s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; + s += fa->light_s * (1 << fa->lmshift); + s += (1 << fa->lmshift) * 0.5; + s /= BLOCK_WIDTH * (1 << fa->lmshift); - t = DotProduct(vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t = DotProduct(vec, fa->lmvecs[1]) + fa->lmvecs[1][3]; t -= fa->texturemins[1]; - t += fa->light_t*16; - t += 8; - t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; + t += fa->light_t * (1 << fa->lmshift); + t += (1 << fa->lmshift) * 0.5; + t /= BLOCK_HEIGHT * (1 << fa->lmshift); poly->verts[i][5] = s; poly->verts[i][6] = t; @@ -1205,8 +1206,8 @@ void Vk_CreateSurfaceLightmap (msurface_t *surf) if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB)) return; - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; + smax = (surf->extents[0] >> surf->lmshift) + 1; + tmax = (surf->extents[1] >> surf->lmshift) + 1; if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) ) {