Add full support for HDR/E5BGR9 lighting.

This commit is contained in:
Shpoike 2023-06-29 16:40:18 +01:00
parent 6dd16b99e7
commit 69e7395b0d
8 changed files with 192 additions and 72 deletions

View file

@ -1050,6 +1050,7 @@ static void Mod_LoadLighting (lump_t *l)
unsigned int path_id; unsigned int path_id;
int bspxsize; int bspxsize;
loadmodel->flags &= ~MOD_HDRLIGHTING; //just in case.
loadmodel->lightdata = NULL; loadmodel->lightdata = NULL;
// LordHavoc: check for a .lit file // LordHavoc: check for a .lit file
q_strlcpy(litfilename, loadmodel->name, sizeof(litfilename)); q_strlcpy(litfilename, loadmodel->name, sizeof(litfilename));
@ -1074,13 +1075,29 @@ static void Mod_LoadLighting (lump_t *l)
{ {
if (8+l->filelen*3 == com_filesize) if (8+l->filelen*3 == com_filesize)
{ {
Con_DPrintf2("%s loaded\n", litfilename); Con_DPrintf2("%s loaded (ldr)\n", litfilename);
loadmodel->lightdata = data + 8; loadmodel->lightdata = data + 8;
loadmodel->lightdatasamples = l->filelen;
return; return;
} }
Hunk_FreeToLowMark(mark); Hunk_FreeToLowMark(mark);
Con_Printf("Outdated .lit file (%s should be %u bytes, not %u)\n", litfilename, 8+l->filelen*3, (unsigned)com_filesize); Con_Printf("Outdated .lit file (%s should be %u bytes, not %u)\n", litfilename, 8+l->filelen*3, (unsigned)com_filesize);
} }
else if (i == 0x10001)
{
if (8+l->filelen*4 == com_filesize)
{
Con_DPrintf2("%s loaded (hdr)\n", litfilename);
loadmodel->lightdata = data + 8;
loadmodel->lightdatasamples = l->filelen;
loadmodel->flags |= MOD_HDRLIGHTING;
for (i = 0; i < loadmodel->lightdatasamples; i++)
((int*)loadmodel->lightdata)[i] = LittleLong(((int*)loadmodel->lightdata)[i]);
return;
}
Hunk_FreeToLowMark(mark);
Con_Printf("Outdated .lit file (%s should be %u bytes, not %u)\n", litfilename, 8+l->filelen*4, (unsigned)com_filesize);
}
else else
{ {
Hunk_FreeToLowMark(mark); Hunk_FreeToLowMark(mark);
@ -1094,16 +1111,15 @@ static void Mod_LoadLighting (lump_t *l)
} }
} }
// LordHavoc: no .lit found, expand the white lighting data to color // LordHavoc: no .lit found, expand the white lighting data to color
if (!l->filelen)
return;
// Quake64 bsp lighmap data // Quake64 bsp lighmap data
if (loadmodel->bspversion == BSPVERSION_QUAKE64) if (loadmodel->bspversion == BSPVERSION_QUAKE64 && l->filelen)
{ {
// RGB lightmap samples are packed in 16bits. // RGB lightmap samples are packed in 16bits.
// RRRRR GGGGG BBBBBB // RRRRR GGGGG BBBBBB
loadmodel->lightdata = (byte *) Hunk_AllocName ( (l->filelen / 2)*3, litfilename); loadmodel->lightdata = (byte *) Hunk_AllocName ( (l->filelen / 2)*3, litfilename);
loadmodel->lightdatasamples = (l->filelen / 2);
in = mod_base + l->fileofs; in = mod_base + l->fileofs;
out = loadmodel->lightdata; out = loadmodel->lightdata;
@ -1119,41 +1135,31 @@ static void Mod_LoadLighting (lump_t *l)
return; return;
} }
in = Q1BSPX_FindLump("RGBLIGHTING", &bspxsize);
if (loadmodel->lightdata && bspxsize == l->filelen*3)
{
loadmodel->lightdata = out = (byte *) Hunk_AllocName ( l->filelen*3, litfilename);
memcpy(out, in, l->filelen*3);
Con_DPrintf("bspx lighting loaded\n");
}
else
{
in = Q1BSPX_FindLump("LIGHTING_E5BGR9", &bspxsize); in = Q1BSPX_FindLump("LIGHTING_E5BGR9", &bspxsize);
if (in && bspxsize == l->filelen*4) if (in && (!l->filelen || (bspxsize && bspxsize == l->filelen*4)))
{ //we don't really support hdr lighting, but we downgrade it to ldr whenever there's no rgb data.
//FIXME: don't convert this stuff here. upload the data to the gpu with GL_EXT_shared_exponent (core in gl3)
loadmodel->lightdata = (byte *) Hunk_AllocName ( l->filelen*3, litfilename);
out = loadmodel->lightdata;
Con_DPrintf("bspx hdr->ldr lighting loaded\n");
for (i = 0;i < l->filelen;i++, in+=4)
{ {
static const float rgb9e5tab[32] = { //multipliers for the 9-bit mantissa, according to the biased mantissa loadmodel->lightdata = (byte *) Hunk_AllocName ( bspxsize, litfilename);
//aka: pow(2, biasedexponent - bias-bits) where bias is 15 and bits is 9 loadmodel->lightdatasamples = bspxsize/4;
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), memcpy(loadmodel->lightdata, in, bspxsize);
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), loadmodel->flags |= MOD_HDRLIGHTING;
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), Con_DPrintf("bspx hdr lighting loaded\n");
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), for (i = 0; i < loadmodel->lightdatasamples; i++) //native endian...
}; ((int*)loadmodel->lightdata)[i] = LittleLong(((int*)loadmodel->lightdata)[i]);
unsigned int e5bgr9 = *(unsigned int*)in; return;
float e = rgb9e5tab[e5bgr9>>27] * (1<<7); //we're converting to a scale that holds overbrights, so 1->128, its 2->255ish
*out++ = q_min(255, e*((e5bgr9>> 0)&0x1ff)); //red
*out++ = q_min(255, e*((e5bgr9>> 9)&0x1ff)); //green
*out++ = q_min(255, e*((e5bgr9>>18)&0x1ff)); //blue
} }
in = Q1BSPX_FindLump("RGBLIGHTING", &bspxsize);
if (in && (!l->filelen || (bspxsize && bspxsize == l->filelen*3)))
{
loadmodel->lightdata = (byte *) Hunk_AllocName ( bspxsize, litfilename);
loadmodel->lightdatasamples = bspxsize/3;
memcpy(loadmodel->lightdata, in, bspxsize);
Con_DPrintf("bspx ldr lighting loaded\n");
return;
} }
else if (l->filelen)
{ {
loadmodel->lightdata = (byte *) Hunk_AllocName ( l->filelen*3, litfilename); loadmodel->lightdata = (byte *) Hunk_AllocName ( l->filelen*3, litfilename);
loadmodel->lightdatasamples = l->filelen;
in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
out = loadmodel->lightdata; out = loadmodel->lightdata;
memcpy (in, mod_base + l->fileofs, l->filelen); memcpy (in, mod_base + l->fileofs, l->filelen);
@ -1164,7 +1170,7 @@ static void Mod_LoadLighting (lump_t *l)
*out++ = d; *out++ = d;
*out++ = d; *out++ = d;
} }
} return;
} }
} }
@ -1557,6 +1563,7 @@ static void Mod_LoadFaces (lump_t *l, qboolean bsp2)
unsigned short *lmstyle16 = NULL; unsigned short *lmstyle16 = NULL;
int lumpsize; int lumpsize;
char scalebuf[16]; char scalebuf[16];
int facestyles;
if (bsp2) if (bsp2)
{ {
@ -1674,8 +1681,14 @@ static void Mod_LoadFaces (lump_t *l, qboolean bsp2)
if (loadmodel->bspversion == BSPVERSION_QUAKE64) if (loadmodel->bspversion == BSPVERSION_QUAKE64)
lofs /= 2; // Q64 samples are 16bits instead 8 in normal Quake lofs /= 2; // Q64 samples are 16bits instead 8 in normal Quake
for (facestyles = 0 ; facestyles<MAXLIGHTMAPS && out->styles[facestyles] != INVALID_LIGHTSTYLE ; facestyles++)
; //count the styles so we can bound-check properly.
if (lofs == -1) if (lofs == -1)
out->samples = NULL; out->samples = NULL;
else if (lofs+facestyles*((out->extents[0]>>out->lmshift)+1)*((out->extents[1]>>out->lmshift)+1) > loadmodel->lightdatasamples)
out->samples = NULL; //corrupt...
else if (loadmodel->flags & MOD_HDRLIGHTING)
out->samples = loadmodel->lightdata + (lofs * 4); //spike -- hdr lighting data is 4-aligned
else else
out->samples = loadmodel->lightdata + (lofs * 3); //johnfitz -- lit support via lordhavoc (was "+ i") out->samples = loadmodel->lightdata + (lofs * 3); //johnfitz -- lit support via lordhavoc (was "+ i")
@ -3370,7 +3383,7 @@ void Mod_SetExtraFlags (qmodel_t *mod)
if (!mod) if (!mod)
return; return;
mod->flags &= (0xFF | MF_HOLEY); //only preserve first byte, plus MF_HOLEY mod->flags &= (0xFF | MF_HOLEY | MOD_HDRLIGHTING); //only preserve first byte, plus MF_HOLEY
if (mod->type == mod_alias) if (mod->type == mod_alias)
{ {

View file

@ -161,7 +161,7 @@ typedef struct msurface_s
unsigned short styles[MAXLIGHTMAPS]; unsigned short styles[MAXLIGHTMAPS];
int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
qboolean cached_dlight; // true if dynamic light in cache qboolean cached_dlight; // true if dynamic light in cache
byte *samples; // [numstyles*surfsize] void *samples; // [numstyles*surfsize]
} msurface_t; } msurface_t;
typedef struct mnode_s typedef struct mnode_s
@ -446,6 +446,7 @@ typedef enum {mod_brush, mod_sprite, mod_alias, mod_ext_invalid} modtype_t;
#define MOD_EMITREPLACE 2048 //particle effect completely replaces the model (for flames or whatever). #define MOD_EMITREPLACE 2048 //particle effect completely replaces the model (for flames or whatever).
#define MOD_EMITFORWARDS 4096 //particle effect is emitted forwards, rather than downwards. why down? good question. #define MOD_EMITFORWARDS 4096 //particle effect is emitted forwards, rather than downwards. why down? good question.
//spike //spike
#define MOD_HDRLIGHTING (1u<<13) //spike -- light samples are in e5bgr9 format. int aligned.
typedef struct qmodel_s typedef struct qmodel_s
{ {
@ -526,6 +527,7 @@ typedef struct qmodel_s
byte *visdata; byte *visdata;
byte *lightdata; byte *lightdata;
size_t lightdatasamples;
char *entities; char *entities;
qboolean viswarn; // for Mod_DecompressVis() qboolean viswarn; // for Mod_DecompressVis()

View file

@ -400,13 +400,34 @@ loc0:
if (dist < *maxdist) if (dist < *maxdist)
{ {
// LordHavoc: enhanced to interpolate lighting // 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; 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; float scale, e;
if (cl.worldmodel->flags & MOD_HDRLIGHTING)
{
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),
};
uint32_t *lightmap = (uint32_t*)surf->samples + ((dt>>surf->lmshift) * ((surf->extents[0]>>surf->lmshift)+1) + (ds>>surf->lmshift));
line3 = ((surf->extents[0]>>surf->lmshift)+1);
for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE;maps++)
{
scale = (1<<7) * (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
e = rgb9e5tab[lightmap[ 0]>>27] * scale;r00 += ((lightmap[ 0]>> 0)&0x1ff) * e;g00 += (float) ((lightmap[ 0]>> 9)&0x1ff) * e;b00 += (float) ((lightmap[ 0]>> 9)&0x1ff) * e;
e = rgb9e5tab[lightmap[ 1]>>27] * scale;r01 += ((lightmap[ 1]>> 0)&0x1ff) * e;g01 += (float) ((lightmap[ 1]>> 9)&0x1ff) * e;b01 += (float) ((lightmap[ 1]>> 9)&0x1ff) * e;
e = rgb9e5tab[lightmap[line3+0]>>27] * scale;r10 += ((lightmap[line3+0]>> 0)&0x1ff) * e;g10 += (float) ((lightmap[line3+0]>> 9)&0x1ff) * e;b10 += (float) ((lightmap[line3+0]>> 9)&0x1ff) * e;
e = rgb9e5tab[lightmap[line3+1]>>27] * scale;r11 += ((lightmap[line3+1]>> 0)&0x1ff) * e;g11 += (float) ((lightmap[line3+1]>> 9)&0x1ff) * e;b11 += (float) ((lightmap[line3+1]>> 9)&0x1ff) * e;
lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1);
}
}
else
{
byte *lightmap = surf->samples + ((dt>>surf->lmshift) * ((surf->extents[0]>>surf->lmshift)+1) + (ds>>surf->lmshift))*3; // LordHavoc: *3 for color
line3 = ((surf->extents[0]>>surf->lmshift)+1)*3; line3 = ((surf->extents[0]>>surf->lmshift)+1)*3;
lightmap = surf->samples + ((dt>>surf->lmshift) * ((surf->extents[0]>>surf->lmshift)+1) + (ds>>surf->lmshift))*3; // LordHavoc: *3 for color
for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE;maps++) for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE;maps++)
{ {
scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0; scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
@ -416,6 +437,7 @@ loc0:
r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale; r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;
lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+1)*3; // LordHavoc: *3 for colored lighting lightmap += ((surf->extents[0]>>surf->lmshift)+1) * ((surf->extents[1]>>surf->lmshift)+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))); color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00))); color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));

View file

@ -76,7 +76,7 @@ static struct
{"RGBA4444", "4444", GL_RGBA4,GL_RGBA,GL_UNSIGNED_SHORT_4_4_4_4, 2, 1, 1, NULL}, {"RGBA4444", "4444", GL_RGBA4,GL_RGBA,GL_UNSIGNED_SHORT_4_4_4_4, 2, 1, 1, NULL},
{"RGBA5551", "5551", GL_RGB5_A1,GL_RGBA,GL_UNSIGNED_SHORT_5_5_5_1, 2, 1, 1, NULL}, {"RGBA5551", "5551", GL_RGB5_A1,GL_RGBA,GL_UNSIGNED_SHORT_5_5_5_1, 2, 1, 1, NULL},
{"L8", "LUM8", GL_LUMINANCE8,GL_LUMINANCE,GL_UNSIGNED_BYTE, 1, 1, 1, NULL}, {"L8", "LUM8", GL_LUMINANCE8,GL_LUMINANCE,GL_UNSIGNED_BYTE, 1, 1, 1, NULL},
{"E5BGR9", "EXP5", GL_RGB9_E5,GL_RGB,GL_UNSIGNED_INT_5_9_9_9_REV, 4, 1, 1, &gl_texture_rgtc/*gl3*/}, {"E5BGR9", "EXP5", GL_RGB9_E5,GL_RGB,GL_UNSIGNED_INT_5_9_9_9_REV, 4, 1, 1, &gl_texture_e5bgr9},
#if defined(GL_EXT_texture_compression_s3tc) || defined(GL_EXT_texture_compression_dxt1) #if defined(GL_EXT_texture_compression_s3tc) || defined(GL_EXT_texture_compression_dxt1)
{"BC1_RGBA", "BC1", GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,0,0, 8, 4, 4, &gl_texture_s3tc}, {"BC1_RGBA", "BC1", GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,0,0, 8, 4, 4, &gl_texture_s3tc},
#endif #endif
@ -1469,6 +1469,9 @@ static void TexMgr_LoadLightmap (gltexture_t *glt, byte *data)
{ {
// upload it // upload it
GL_Bind (glt); GL_Bind (glt);
if (gl_lightmap_format == GL_RGB9_E5)
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB9_E5, glt->width, glt->height, 0, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, data);
else
glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, glt->width, glt->height, 0, gl_lightmap_format, GL_UNSIGNED_BYTE, data); glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, glt->width, glt->height, 0, gl_lightmap_format, GL_UNSIGNED_BYTE, data);
// set filter modes // set filter modes

View file

@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define TEXPREF_ALLOWMISSING 0x2000 // TexMgr_LoadImage should return NULL if anything goes wrong (for use with SRC_EXTERNAL). #define TEXPREF_ALLOWMISSING 0x2000 // TexMgr_LoadImage should return NULL if anything goes wrong (for use with SRC_EXTERNAL).
enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA, SRC_EXTERNAL, SRC_FIRSTCOMPRESSED}; enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA, SRC_EXTERNAL, SRC_FIRSTCOMPRESSED};
extern qboolean gl_texture_s3tc, gl_texture_rgtc, gl_texture_bptc, gl_texture_etc2, gl_texture_astc; extern qboolean gl_texture_s3tc, gl_texture_rgtc, gl_texture_bptc, gl_texture_etc2, gl_texture_astc, gl_texture_e5bgr9;
typedef uintptr_t src_offset_t; typedef uintptr_t src_offset_t;

View file

@ -67,7 +67,7 @@ static int gl_version_major;
static int gl_version_minor; static int gl_version_minor;
static const char *gl_extensions; static const char *gl_extensions;
qboolean gl_texture_s3tc, gl_texture_rgtc, gl_texture_bptc, gl_texture_etc2, gl_texture_astc; qboolean gl_texture_s3tc, gl_texture_rgtc, gl_texture_bptc, gl_texture_etc2, gl_texture_astc, gl_texture_e5bgr9;
static vmode_t modelist[MAX_MODE_LIST]; static vmode_t modelist[MAX_MODE_LIST];
static int nummodes; static int nummodes;
@ -1168,6 +1168,7 @@ static void GL_CheckExtensions (void)
gl_texture_bptc = GL_CompressedTexImage2D && (gl_version_major > 4 || (gl_version_major == 4 && gl_version_minor >= 2) || GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_compression_bptc")); gl_texture_bptc = GL_CompressedTexImage2D && (gl_version_major > 4 || (gl_version_major == 4 && gl_version_minor >= 2) || GL_ParseExtensionList(gl_extensions, "GL_ARB_texture_compression_bptc"));
gl_texture_etc2 = GL_CompressedTexImage2D && (gl_version_major > 4 || (gl_version_major == 4 && gl_version_minor >= 3) || GL_ParseExtensionList(gl_extensions, "GL_ARB_ES3_compatibility")); gl_texture_etc2 = GL_CompressedTexImage2D && (gl_version_major > 4 || (gl_version_major == 4 && gl_version_minor >= 3) || GL_ParseExtensionList(gl_extensions, "GL_ARB_ES3_compatibility"));
gl_texture_astc = GL_CompressedTexImage2D && ( GL_ParseExtensionList(gl_extensions, "GL_ARB_ES3_2_compatibility") || GL_ParseExtensionList(gl_extensions, "GL_KHR_texture_compression_astc_ldr")); gl_texture_astc = GL_CompressedTexImage2D && ( GL_ParseExtensionList(gl_extensions, "GL_ARB_ES3_2_compatibility") || GL_ParseExtensionList(gl_extensions, "GL_KHR_texture_compression_astc_ldr"));
gl_texture_e5bgr9 = gl_version_major >= 3;
// GLSL // GLSL
// //

View file

@ -955,10 +955,16 @@ void GL_BuildLightmaps (void)
last_lightmap_allocated = 0; last_lightmap_allocated = 0;
lightmap_count = 0; lightmap_count = 0;
if (gl_texture_e5bgr9)// && cl.worldmodel && (cl.worldmodel->flags&MOD_HDRLIGHTING))
gl_lightmap_format = GL_RGB9_E5; //requires gl3, allowing for hdr lighting.
else
gl_lightmap_format = GL_RGBA;//FIXME: hardcoded for now! gl_lightmap_format = GL_RGBA;//FIXME: hardcoded for now!
switch (gl_lightmap_format) switch (gl_lightmap_format)
{ {
case GL_RGB9_E5:
lightmap_bytes = 4;
break;
case GL_RGBA: case GL_RGBA:
lightmap_bytes = 4; lightmap_bytes = 4;
break; break;
@ -1224,7 +1230,6 @@ void R_BuildLightMap (qmodel_t *model, msurface_t *surf, byte *dest, int stride)
int smax, tmax; int smax, tmax;
int r,g,b; int r,g,b;
int i, j, size; int i, j, size;
byte *lightmap;
unsigned scale; unsigned scale;
int maps; int maps;
unsigned *bl; unsigned *bl;
@ -1234,7 +1239,6 @@ void R_BuildLightMap (qmodel_t *model, msurface_t *surf, byte *dest, int stride)
smax = (surf->extents[0]>>surf->lmshift)+1; smax = (surf->extents[0]>>surf->lmshift)+1;
tmax = (surf->extents[1]>>surf->lmshift)+1; tmax = (surf->extents[1]>>surf->lmshift)+1;
size = smax*tmax; size = smax*tmax;
lightmap = surf->samples;
if (model->lightdata) if (model->lightdata)
{ {
@ -1242,8 +1246,37 @@ void R_BuildLightMap (qmodel_t *model, msurface_t *surf, byte *dest, int stride)
memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
// add all the lightmaps // add all the lightmaps
if (lightmap) if (!surf->samples)
; //unlit surfaces are black... FIXME: unless lit water (could be new-qbsp + old-light)...
else if (model->flags & MOD_HDRLIGHTING)
{ {
uint32_t *lightmap = surf->samples;
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ;
maps++)
{
scale = d_lightstylevalue[surf->styles[maps]];
surf->cached_light[maps] = scale; // 8.8 fraction
bl = blocklights; //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).
for (i=0 ; i<size ; i++)
{
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),
};
uint32_t e5bgr9 = *lightmap++;
float e = rgb9e5tab[e5bgr9>>27] * (1<<7) * scale; //we're converting to a scale that holds overbrights, so 1->128, its 2->255ish
*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] != INVALID_LIGHTSTYLE ; for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != INVALID_LIGHTSTYLE ;
maps++) maps++)
{ {
@ -1275,6 +1308,41 @@ void R_BuildLightMap (qmodel_t *model, msurface_t *surf, byte *dest, int stride)
// store: // store:
switch (gl_lightmap_format) switch (gl_lightmap_format)
{ {
case GL_RGB9_E5:
{
int e;
float m;
float scale, identity = 1u<<((gl_overbright.value?8:7)+8); //overbright is redundant with this, but its easier to leave it than conditionally block it.
stride -= smax * 4;
bl = blocklights;
for (i=0 ; i<tmax ; i++, dest += stride)
{
for (j=0 ; j<smax ; j++)
{
e = 0;
m = q_max(q_max(bl[0], bl[1]), bl[2])/identity;
if (m >= 0.5)
{ //positive exponent
while (m >= (1<<(e)) && e < 30-15) //don't do nans.
e++;
}
else
{ //negative exponent...
while (m < 1/(1<<-e) && e > -15) //don't do denormals.
e--;
}
scale = pow(2, e-9);
scale *= identity;
*(unsigned int *)dest = ((e+15)<<27) |
CLAMP(0, (int)(bl[0]/scale + 0.5), 0x1ff)<<0 |
CLAMP(0, (int)(bl[1]/scale + 0.5), 0x1ff)<<9 |
CLAMP(0, (int)(bl[2]/scale + 0.5), 0x1ff)<<18;
bl += 3;
dest += 4;
}
}
}
break;
case GL_RGBA: case GL_RGBA:
stride -= smax * 4; stride -= smax * 4;
bl = blocklights; bl = blocklights;
@ -1348,6 +1416,10 @@ static void R_UploadLightmap(int lmap)
lm->modified = false; lm->modified = false;
if (gl_lightmap_format == GL_RGB9_E5)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lm->rectchange.t, LMBLOCK_WIDTH, lm->rectchange.h, GL_RGB,
GL_UNSIGNED_INT_5_9_9_9_REV, lm->data+lm->rectchange.t*LMBLOCK_WIDTH*lightmap_bytes);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lm->rectchange.t, LMBLOCK_WIDTH, lm->rectchange.h, gl_lightmap_format, glTexSubImage2D(GL_TEXTURE_2D, 0, 0, lm->rectchange.t, LMBLOCK_WIDTH, lm->rectchange.h, gl_lightmap_format,
GL_UNSIGNED_BYTE, lm->data+lm->rectchange.t*LMBLOCK_WIDTH*lightmap_bytes); GL_UNSIGNED_BYTE, lm->data+lm->rectchange.t*LMBLOCK_WIDTH*lightmap_bytes);
lm->rectchange.l = LMBLOCK_WIDTH; lm->rectchange.l = LMBLOCK_WIDTH;
@ -1439,6 +1511,10 @@ void R_RebuildAllLightmaps (void)
else else
{ {
GL_Bind (lightmaps[i].texture); GL_Bind (lightmaps[i].texture);
if (gl_lightmap_format == GL_RGB9_E5)
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, GL_RGB,
GL_UNSIGNED_INT_5_9_9_9_REV, lightmaps[i].data);
else
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, gl_lightmap_format, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, gl_lightmap_format,
GL_UNSIGNED_BYTE, lightmaps[i].data); GL_UNSIGNED_BYTE, lightmaps[i].data);
} }

View file

@ -195,6 +195,9 @@ QuakeSpasm-Spiked
"emiteffect" field - to specify a constantly emitting effect. "emiteffect" field - to specify a constantly emitting effect.
"traileffect" field - for particles any time the entity moves. "traileffect" field - for particles any time the entity moves.
o Optional HDR lighting (via LIGHTING_E5BGR9 bspx lump), allowing for much
greater overbrights without stacking styles (to compensate for overly dark textures).
-------- --------
4. Todo 4. Todo