diff --git a/src/gl_model.h b/src/gl_model.h index 7590d129e..661f87aa6 100644 --- a/src/gl_model.h +++ b/src/gl_model.h @@ -465,6 +465,8 @@ typedef enum #define EF_TRACER2 64 // orange split trail + rotate #define EF_TRACER3 128 // purple trail +#define MOD_HDRLIGHTING (1u<<13) //spike -- light samples are in e5bgr9 format. int aligned. + #define MAX_SIMPLE_TEXTURES 5 #define MAX_TEXTURE_ARRAYS_PER_MODEL 64 @@ -542,6 +544,7 @@ typedef struct model_s { byte* visdata; int visdata_length; byte* lightdata; + size_t lightdatasamplesize; int bspversion; qbool isworldmodel; diff --git a/src/r_brushmodel_load.c b/src/r_brushmodel_load.c index 4d4915e0e..614bd043f 100644 --- a/src/r_brushmodel_load.c +++ b/src/r_brushmodel_load.c @@ -141,7 +141,7 @@ static void SetSurfaceLighting(model_t* loadmodel, msurface_t* out, byte* styles out->samples = NULL; } else { - out->samples = loadmodel->lightdata + (loadmodel->bspversion == HL_BSPVERSION ? i : i * 3); + out->samples = loadmodel->lightdata + (loadmodel->bspversion == HL_BSPVERSION ? i : i * loadmodel->lightdatasamplesize); } } @@ -243,24 +243,38 @@ static void Mod_LoadLighting(model_t* loadmodel, lump_t* l, byte* mod_base, bspx if (load_inline) { int threshold = (lightmode == 1 ? 255 : lightmode == 2 ? 170 : 128); int lumpsize; - byte *rgb = Mod_BSPX_FindLump(bspx_header, "RGBLIGHTING", &lumpsize, mod_base); - // Sanity-check size if vanilla lit exists - if (rgb && lumpsize % 3 == 0 && (lumpsize == l->filelen * 3 || l->filelen <= 0)) { - loadmodel->lightdata = (byte *) Hunk_AllocName(lumpsize, loadmodel->name); + byte *rgb; + + rgb = Mod_BSPX_FindLump(bspx_header, "LIGHTING_E5BGR9", &lumpsize, mod_base); + if (rgb && lumpsize % 4 == 0 && (lumpsize == l->filelen * 4 || l->filelen <= 0)) { + loadmodel->lightdata = (byte *) Hunk_AllocName (lumpsize, loadmodel->name); + loadmodel->lightdatasamplesize = 4; memcpy(loadmodel->lightdata, rgb, lumpsize); - // we trust the inline RGB data to be bug free so we don't check it against the mono lightmap - // what we do though is prevent color wash-out in brightly lit areas - // (one day we may do it in R_BuildLightMap instead) - out = loadmodel->lightdata; - for (i = 0; i < lumpsize / 3; i++, out += 3) { - int m = max(out[0], max(out[1], out[2])); - if (m > threshold) { - out[0] = out[0] * threshold / m; - out[1] = out[1] * threshold / m; - out[2] = out[2] * threshold / m; + loadmodel->flags |= MOD_HDRLIGHTING; + for (i = 0; i < lumpsize / 4; i++) { //native endian... + ((int*)loadmodel->lightdata)[i] = LittleLong(((int*)loadmodel->lightdata)[i]); + } + } else { + rgb = Mod_BSPX_FindLump(bspx_header, "RGBLIGHTING", &lumpsize, mod_base); + // Sanity-check size if vanilla lit exists + if (rgb && lumpsize % 3 == 0 && (lumpsize == l->filelen * 3 || l->filelen <= 0)) { + loadmodel->lightdata = (byte *) Hunk_AllocName(lumpsize, loadmodel->name); + loadmodel->lightdatasamplesize = 3; + memcpy(loadmodel->lightdata, rgb, lumpsize); + // we trust the inline RGB data to be bug free so we don't check it against the mono lightmap + // what we do though is prevent color wash-out in brightly lit areas + // (one day we may do it in R_BuildLightMap instead) + out = loadmodel->lightdata; + for (i = 0; i < lumpsize / 3; i++, out += 3) { + int m = max(out[0], max(out[1], out[2])); + if (m > threshold) { + out[0] = out[0] * threshold / m; + out[1] = out[1] * threshold / m; + out[2] = out[2] * threshold / m; + } } + // all done, but we let them override it with a .lit } - // all done, but we let them override it with a .lit } } @@ -285,6 +299,7 @@ static void Mod_LoadLighting(model_t* loadmodel, lump_t* l, byte* mod_base, bspx Com_Printf("Static coloured lighting loaded\n"); } loadmodel->lightdata = data + 8; + loadmodel->lightdatasamplesize = 3; in = mod_base + l->fileofs; out = loadmodel->lightdata; @@ -345,6 +360,7 @@ static void Mod_LoadLighting(model_t* loadmodel, lump_t* l, byte* mod_base, bspx //no .lit found, expand the white lighting data to color loadmodel->lightdata = (byte *) Hunk_AllocName (l->filelen * 3, va("%s_@lightdata", loadmodel->name)); + loadmodel->lightdatasamplesize = 3; in = mod_base + l->fileofs; out = loadmodel->lightdata; for (i = 0; i < l->filelen; i++, out += 3) { diff --git a/src/r_lighting.h b/src/r_lighting.h index 724466aba..4c645cd7f 100644 --- a/src/r_lighting.h +++ b/src/r_lighting.h @@ -34,6 +34,13 @@ void R_RenderDlights(void); void R_LightEntity(entity_t* ent); extern unsigned int d_lightstylevalue[256]; // 8.8 fraction of base light value +static const float rgb9e5tab[32] = { //multipliers for the 9-bit mantissa, according to the biased mantissa + //aka: pow(2, biasedexponent - bias-bits) where bias is 15 and bits is 9 + 1.0/(1<<24), 1.0/(1<<23), 1.0/(1<<22), 1.0/(1<<21), 1.0/(1<<20), 1.0/(1<<19), 1.0/(1<<18), 1.0/(1<<17), + 1.0/(1<<16), 1.0/(1<<15), 1.0/(1<<14), 1.0/(1<<13), 1.0/(1<<12), 1.0/(1<<11), 1.0/(1<<10), 1.0/(1<<9), + 1.0/(1<<8), 1.0/(1<<7), 1.0/(1<<6), 1.0/(1<<5), 1.0/(1<<4), 1.0/(1<<3), 1.0/(1<<2), 1.0/(1<<1), + 1.0, 1.0*(1<<1), 1.0*(1<<2), 1.0*(1<<3), 1.0*(1<<4), 1.0*(1<<5), 1.0*(1<<6), 1.0*(1<<7), +}; extern cvar_t r_dynamic; #define R_NoLighting() (r_dynamic.integer == 0) diff --git a/src/r_lightmaps.c b/src/r_lightmaps.c index 4d7c615d3..976ab22a5 100644 --- a/src/r_lightmaps.c +++ b/src/r_lightmaps.c @@ -210,10 +210,9 @@ static void R_AddDynamicLights(msurface_t *surf) } //Combine and scale multiple lightmaps into the 8.8 format in blocklights -static void R_BuildLightMap(msurface_t *surf, byte *dest, int stride) +static void R_BuildLightMap(msurface_t *surf, byte *dest, int stride, uint32_t flags) { int smax, tmax, i, j, size, blocksize, maps; - byte *lightmap; unsigned scale, *bl; qbool fullbright = false; @@ -225,7 +224,6 @@ static void R_BuildLightMap(msurface_t *surf, byte *dest, int stride) tmax = (surf->extents[1] >> surf->lmshift) + 1; size = smax * tmax; blocksize = size * 3; - lightmap = surf->samples; // check for full bright or no light data fullbright = (R_FullBrightAllowed() || !cl.worldmodel || !cl.worldmodel->lightdata); @@ -241,16 +239,37 @@ static void R_BuildLightMap(msurface_t *surf, byte *dest, int stride) } // add all the lightmaps - for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - - if (!fullbright && lightmap) { + if (flags & MOD_HDRLIGHTING) { + uint32_t *lightmap = (uint32_t *)surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + // it sucks that blocklights is an int array. we can still massively + // overbright though, just not underbright quite as accurately + // (still quite a bit more than rgb8 precision there). bl = blocklights; - for (i = 0; i < blocksize; i++) { - *bl++ += lightmap[i] * scale; + for (i=0 ; i128, its 2->255ish + float e = rgb9e5tab[e5bgr9>>27] * (1<<7) * scale; + *bl++ += e*((e5bgr9>> 0)&0x1ff); //red + *bl++ += e*((e5bgr9>> 9)&0x1ff); //green + *bl++ += e*((e5bgr9>>18)&0x1ff); //blue + } + } + } else { + byte *lightmap = surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + + if (!fullbright && lightmap) { + bl = blocklights; + for (i = 0; i < blocksize; i++) { + *bl++ += lightmap[i] * scale; + } + lightmap += blocksize; // skip to next lightmap } - lightmap += blocksize; // skip to next lightmap } } @@ -392,7 +411,7 @@ void R_RenderDynamicLightmaps(msurface_t *fa, qbool world) theRect->h = fa->light_t - theRect->t + tmax; } base = lm->rawdata + (fa->light_t * LIGHTMAP_WIDTH + fa->light_s) * 4; - R_BuildLightMap (fa, base, LIGHTMAP_WIDTH * 4); + R_BuildLightMap (fa, base, LIGHTMAP_WIDTH * 4, world ? cl.worldmodel->flags : 0); } void R_LightmapFrameInit(void) @@ -749,7 +768,6 @@ static void R_BuildSurfaceDisplayList(model_t* currentmodel, msurface_t *fa) static void R_BuildLightmapData(msurface_t* surf, int surfnum) { lightmap_data_t* lm = &lightmaps[surf->lightmaptexturenum]; - byte* lightmap = surf->samples; unsigned int smax = (surf->extents[0] >> surf->lmshift) + 1; unsigned int tmax = (surf->extents[1] >> surf->lmshift) + 1; unsigned int lightmap_flags; @@ -775,20 +793,35 @@ static void R_BuildLightmapData(msurface_t* surf, int surfnum) source[0] = source[1] = source[2] = 0; source[3] = lightmap_flags; - if (lightmap) { - for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { - size_t lightmap_index = (maps * smax * tmax + t * smax + s) * 3; - - source[0] |= ((unsigned int)lightmap[lightmap_index + 0]) << (8 * maps); - source[1] |= ((unsigned int)lightmap[lightmap_index + 1]) << (8 * maps); - source[2] |= ((unsigned int)lightmap[lightmap_index + 2]) << (8 * maps); + if (surf->samples) { + if (surfnum != -1 && cl.worldmodel->flags & MOD_HDRLIGHTING) { + uint32_t* lightmap = (uint32_t *)surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { + size_t lightmap_index = (maps * smax * tmax + t * smax + s); + uint32_t e5bgr9 = lightmap[lightmap_index]; + //we're converting to a scale that holds overbrights, so 1->128, its 2->255ish + float e = rgb9e5tab[e5bgr9>>27] * (1<<7) * (float) d_lightstylevalue[surf->styles[maps]] * 1.0f / 256.0f; + // should not clamp here, but changing the light compute shader can be done later + source[0] += (unsigned int)bound(0, e*((e5bgr9>> 0)&0x1ff), 0xff) << (8 * maps); + source[1] += (unsigned int)bound(0, e*((e5bgr9>> 9)&0x1ff), 0xff) << (8 * maps); + source[2] += (unsigned int)bound(0, e*((e5bgr9>>18)&0x1ff), 0xff) << (8 * maps); + } + } else { + byte* lightmap = surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { + size_t lightmap_index = (maps * smax * tmax + t * smax + s) * 3; + + source[0] |= ((unsigned int)lightmap[lightmap_index + 0]) << (8 * maps); + source[1] |= ((unsigned int)lightmap[lightmap_index + 1]) << (8 * maps); + source[2] |= ((unsigned int)lightmap[lightmap_index + 2]) << (8 * maps); + } } } } } } -static void R_LightmapCreateForSurface(msurface_t *surf, int surfnum) +static void R_LightmapCreateForSurface(msurface_t *surf, int surfnum, uint32_t flags) { int smax, tmax; byte *base; @@ -811,7 +844,7 @@ static void R_LightmapCreateForSurface(msurface_t *surf, int surfnum) base = lightmaps[surf->lightmaptexturenum].rawdata + (surf->light_t * LIGHTMAP_WIDTH + surf->light_s) * 4; numdlights = 0; R_BuildLightmapData(surf, surfnum); - R_BuildLightMap(surf, base, LIGHTMAP_WIDTH * 4); + R_BuildLightMap(surf, base, LIGHTMAP_WIDTH * 4, flags); } static int R_LightmapSurfaceSortFunction(const void* lhs_, const void* rhs_) @@ -917,7 +950,7 @@ void R_BuildLightmaps(void) qbool isTurb = (surfaces[i]->flags & SURF_DRAWTURB); if (!isTurb) { - R_LightmapCreateForSurface(surfaces[i], m->isworldmodel ? surfaces[i]->surfacenum : -1); + R_LightmapCreateForSurface(surfaces[i], m->isworldmodel ? surfaces[i]->surfacenum : -1, m->flags); } R_BuildSurfaceDisplayList(m, surfaces[i]); } @@ -939,7 +972,7 @@ void R_BuildLightmaps(void) } if (!isTurb || !(m->surfaces[i].texinfo->flags & TEX_SPECIAL)) { - R_LightmapCreateForSurface(m->surfaces + i, m->isworldmodel ? m->surfaces[i].surfacenum : -1); + R_LightmapCreateForSurface(m->surfaces + i, m->isworldmodel ? m->surfaces[i].surfacenum : -1, m->flags); } R_BuildSurfaceDisplayList(m, m->surfaces + i); } diff --git a/src/r_rlight.c b/src/r_rlight.c index f12c1535e..cd0e15604 100644 --- a/src/r_rlight.c +++ b/src/r_rlight.c @@ -321,20 +321,32 @@ static void R_LightFromSurface(msurface_t* surf, int ds, int dt, vec3_t color) { if (surf->samples) { // LordHavoc: enhanced to interpolate lighting - byte *lightmap; int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0; float scale; line3 = ((surf->extents[0] >> 4) + 1) * 3; - lightmap = surf->samples + ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3; // LordHavoc: *3 for color - - for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { - scale = (float)d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0; - r00 += (float)lightmap[0] * scale; g00 += (float)lightmap[1] * scale; b00 += (float)lightmap[2] * scale; - r01 += (float)lightmap[3] * scale; g01 += (float)lightmap[4] * scale; b01 += (float)lightmap[5] * scale; - r10 += (float)lightmap[line3 + 0] * scale; g10 += (float)lightmap[line3 + 1] * scale; b10 += (float)lightmap[line3 + 2] * scale; - r11 += (float)lightmap[line3 + 3] * scale; g11 += (float)lightmap[line3 + 4] * scale; b11 += (float)lightmap[line3 + 5] * scale; - lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1) * 3; // LordHavoc: *3 for colored lighting + if (cl.worldmodel->flags & MOD_HDRLIGHTING) { + uint32_t *lightmap = (uint32_t*)surf->samples + (dt * (surf->extents[0]+1) + ds); + line3 = (surf->extents[0]+1); + for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { + float e; + scale = (1<<7) * (float) d_lightstylevalue[surf->styles[maps]] * 1.0f / 256.0f; + e = rgb9e5tab[lightmap[ 0]>>27] * scale;r00 += ((lightmap[ 0]>> 0)&0x1ff) * e;g00 += ((lightmap[ 0]>> 9)&0x1ff) * e;b00 += ((lightmap[ 0]>> 9)&0x1ff) * e; + e = rgb9e5tab[lightmap[ 1]>>27] * scale;r01 += ((lightmap[ 1]>> 0)&0x1ff) * e;g01 += ((lightmap[ 1]>> 9)&0x1ff) * e;b01 += ((lightmap[ 1]>> 9)&0x1ff) * e; + e = rgb9e5tab[lightmap[line3+0]>>27] * scale;r10 += ((lightmap[line3+0]>> 0)&0x1ff) * e;g10 += ((lightmap[line3+0]>> 9)&0x1ff) * e;b10 += ((lightmap[line3+0]>> 9)&0x1ff) * e; + e = rgb9e5tab[lightmap[line3+1]>>27] * scale;r11 += ((lightmap[line3+1]>> 0)&0x1ff) * e;g11 += ((lightmap[line3+1]>> 9)&0x1ff) * e;b11 += ((lightmap[line3+1]>> 9)&0x1ff) * e; + lightmap += (surf->extents[0]+1) * (surf->extents[1]+1); + } + } else { + byte *lightmap = surf->samples + ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3; // LordHavoc: *3 for color + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) { + scale = (float)d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0; + r00 += (float)lightmap[0] * scale; g00 += (float)lightmap[1] * scale; b00 += (float)lightmap[2] * scale; + r01 += (float)lightmap[3] * scale; g01 += (float)lightmap[4] * scale; b01 += (float)lightmap[5] * scale; + r10 += (float)lightmap[line3 + 0] * scale; g10 += (float)lightmap[line3 + 1] * scale; b10 += (float)lightmap[line3 + 2] * scale; + r11 += (float)lightmap[line3 + 3] * scale; g11 += (float)lightmap[line3 + 4] * scale; b11 += (float)lightmap[line3 + 5] * scale; + lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1) * 3; // LordHavoc: *3 for colored lighting + } } color[0] += (float)((int)((((((((r11 - r10) * dsfrac) >> 4) + r10) - ((((r01 - r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01 - r00) * dsfrac) >> 4) + r00)));