rtx: fix missing emissive textures, fix #129

Try to match textures from all wads referenced in worldspawn.wad.
This commit is contained in:
Ivan Avdeev 2021-10-22 10:35:00 -07:00 committed by Ivan Avdeev
parent 7bbf1ea94d
commit 26caa39488
1 changed files with 188 additions and 130 deletions

View File

@ -52,131 +52,6 @@ void VK_LightsShutdown( void ) {
clusterBitMapShutdown();
}
static int lookupTextureF( const char *fmt, ...) {
int tex_id = 0;
char buffer[1024];
va_list argptr;
va_start( argptr, fmt );
vsnprintf( buffer, sizeof buffer, fmt, argptr );
va_end( argptr );
tex_id = VK_FindTexture(buffer);
gEngine.Con_Reportf("Looked up texture %s -> %d\n", buffer, tex_id);
return tex_id;
}
static void loadRadData( const model_t *map, const char *fmt, ... ) {
fs_offset_t size;
char *data;
byte *buffer;
char filename[1024];
va_list argptr;
va_start( argptr, fmt );
vsnprintf( filename, sizeof filename, fmt, argptr );
va_end( argptr );
buffer = gEngine.COM_LoadFile( filename, &size, false);
if (!buffer) {
gEngine.Con_Printf(S_ERROR "Couldn't load RAD data from file %s, the map will be completely black\n", filename);
return;
}
gEngine.Con_Reportf("Loading RAD data from file %s\n", filename);
data = (char*)buffer;
for (;;) {
string name;
float r=0, g=0, b=0, scale=0;
int num;
char* line_end;
while (*data != '\0' && isspace(*data)) ++data;
if (*data == '\0')
break;
line_end = Q_strchr(data, '\n');
if (line_end) *line_end = '\0';
name[0] = '\0';
num = sscanf(data, "%s %f %f %f %f", name, &r, &g, &b, &scale);
gEngine.Con_Printf("raw rad entry (%d): %s %f %f %f %f\n", num, name, r, g, b, scale);
if (Q_strstr(name, "//") != NULL) {
num = 0;
}
if (num == 2) {
r = g = b;
} else if (num == 5) {
scale /= 255.f;
r *= scale;
g *= scale;
b *= scale;
} else if (num == 4) {
// Ok, rgb only, no scaling
} else {
gEngine.Con_Printf( "skipping rad entry %s\n", name[0] ? name : "(empty)" );
num = 0;
}
if (num != 0) {
gEngine.Con_Printf("rad entry (%d): %s %f %f %f (%f)\n", num, name, r, g, b, scale);
{
const char *wad_name = NULL;
char *texture_name = Q_strchr(name, '/');
string texname;
int tex_id;
const qboolean enabled = (r != 0 || g != 0 || b != 0);
if (!texture_name) {
texture_name = name;
} else {
// name is now just a wad name
texture_name[0] = '\0';
wad_name = name;
texture_name += 1;
}
// Try bsp texture first
tex_id = lookupTextureF("#%s:%s.mip", map->name, texture_name);
// Try wad texture if bsp is not there
if (!tex_id) {
if (!wad_name)
wad_name = "halflife";
tex_id = lookupTextureF("%s.wad/%s.mip", wad_name, texture_name);
}
if (tex_id) {
vk_emissive_texture_t *const etex = g_lights.map.emissive_textures + tex_id;
ASSERT(tex_id < MAX_TEXTURES);
etex->emissive[0] = r;
etex->emissive[1] = g;
etex->emissive[2] = b;
etex->set = enabled;
// See DIRECT_SCALE in qrad/lightmap.c
VectorScale(etex->emissive, 0.1f, etex->emissive);
if (!enabled)
gEngine.Con_Reportf("rad entry %s disabled due to zero intensity\n", name);
}
}
}
if (!line_end)
break;
data = line_end + 1;
}
Mem_Free(buffer);
}
#define ENT_PROP_LIST(X) \
X(0, vec3_t, origin, Vec3) \
X(1, vec3_t, angles, Vec3) \
@ -187,12 +62,14 @@ static void loadRadData( const model_t *map, const char *fmt, ... ) {
X(6, float, _cone, Float) \
X(7, float, _cone2, Float) \
X(8, int, _sky, Int) \
X(9, string, wad, WadList) \
typedef enum {
Unknown = 0,
Light,
LightSpot,
LightEnvironment,
Worldspawn,
Ignored,
} class_name_e;
@ -209,19 +86,54 @@ typedef enum {
#undef DECLARE_FIELD
} fields_read_e;
static unsigned parseEntPropFloat(const string value, float *out, unsigned bit) {
static unsigned parseEntPropWadList(const char* value, string *out, unsigned bit) {
int dst_left = sizeof(string) - 2; // ; \0
char *dst = *out;
*dst = '\0';
gEngine.Con_Reportf("WADS: %s\n", value);
for (; *value;) {
const char *file_begin = value;
for (; *value && *value != ';'; ++value) {
if (*value == '\\' || *value == '/')
file_begin = value + 1;
}
{
const int len = value - file_begin;
gEngine.Con_Reportf("WAD: %.*s\n", len, file_begin);
if (len < dst_left) {
Q_strncpy(dst, file_begin, len + 1);
dst += len;
dst[0] = ';';
dst++;
dst[0] = '\0';
dst_left -= len;
}
}
if (*value) value++;
}
gEngine.Con_Reportf("wad list: %s\n", *out);
return bit;
}
static unsigned parseEntPropFloat(const char* value, float *out, unsigned bit) {
return (1 == sscanf(value, "%f", out)) ? bit : 0;
}
static unsigned parseEntPropInt(const string value, int *out, unsigned bit) {
static unsigned parseEntPropInt(const char* value, int *out, unsigned bit) {
return (1 == sscanf(value, "%d", out)) ? bit : 0;
}
static unsigned parseEntPropVec3(const string value, vec3_t *out, unsigned bit) {
static unsigned parseEntPropVec3(const char* value, vec3_t *out, unsigned bit) {
return (3 == sscanf(value, "%f %f %f", &(*out)[0], &(*out)[1], &(*out)[2])) ? bit : 0;
}
static unsigned parseEntPropRgbav(const string value, vec3_t *out, unsigned bit) {
static unsigned parseEntPropRgbav(const char* value, vec3_t *out, unsigned bit) {
float scale = 1.f;
const int components = sscanf(value, "%f %f %f %f", &(*out)[0], &(*out)[1], &(*out)[2], &scale);
if (components == 1) {
@ -243,13 +155,15 @@ static unsigned parseEntPropRgbav(const string value, vec3_t *out, unsigned bit)
return 0;
}
static unsigned parseEntPropClassname(const string value, class_name_e *out, unsigned bit) {
static unsigned parseEntPropClassname(const char* value, class_name_e *out, unsigned bit) {
if (Q_strcmp(value, "light") == 0) {
*out = Light;
} else if (Q_strcmp(value, "light_spot") == 0) {
*out = LightSpot;
} else if (Q_strcmp(value, "light_environment") == 0) {
*out = LightEnvironment;
} else if (Q_strcmp(value, "worldspawn") == 0) {
*out = Worldspawn;
} else {
*out = Ignored;
}
@ -278,6 +192,8 @@ struct {
vk_light_entity_t lights[256];
int single_environment_index;
string wadlist;
} g_light_entities;
enum { NoEnvironmentLights = -1, MoreThanOneEnvironmentLight = -2 };
@ -402,6 +318,10 @@ static void addLightEntity( const entity_props_t *props, unsigned have_fields )
g_light_entities.num_lights++;
}
static void readWorldspawn( const entity_props_t *props ) {
Q_strcpy(g_light_entities.wadlist, props->wad);
}
static void parseStaticLightEntities( void ) {
const model_t* const world = gEngine.pfnGetModelByIndex( 1 );
char *pos;
@ -436,6 +356,10 @@ static void parseStaticLightEntities( void ) {
addLightEntity( &values, have_fields );
break;
case Worldspawn:
readWorldspawn( &values );
break;
case Unknown:
case Ignored:
// Skip
@ -503,6 +427,140 @@ static struct {
} g_lights_bsp = {0};
static int lookupTextureF( const char *fmt, ...) {
int tex_id = 0;
char buffer[1024];
va_list argptr;
va_start( argptr, fmt );
vsnprintf( buffer, sizeof buffer, fmt, argptr );
va_end( argptr );
tex_id = VK_FindTexture(buffer);
gEngine.Con_Reportf("Looked up texture %s -> %d\n", buffer, tex_id);
return tex_id;
}
static void loadRadData( const model_t *map, const char *fmt, ... ) {
fs_offset_t size;
char *data;
byte *buffer;
char filename[1024];
va_list argptr;
va_start( argptr, fmt );
vsnprintf( filename, sizeof filename, fmt, argptr );
va_end( argptr );
buffer = gEngine.COM_LoadFile( filename, &size, false);
if (!buffer) {
gEngine.Con_Printf(S_ERROR "Couldn't load RAD data from file %s, the map will be completely black\n", filename);
return;
}
gEngine.Con_Reportf("Loading RAD data from file %s\n", filename);
data = (char*)buffer;
for (;;) {
string name;
float r=0, g=0, b=0, scale=0;
int num;
char* line_end;
while (*data != '\0' && isspace(*data)) ++data;
if (*data == '\0')
break;
line_end = Q_strchr(data, '\n');
if (line_end) *line_end = '\0';
name[0] = '\0';
num = sscanf(data, "%s %f %f %f %f", name, &r, &g, &b, &scale);
gEngine.Con_Printf("raw rad entry (%d): %s %f %f %f %f\n", num, name, r, g, b, scale);
if (Q_strstr(name, "//") != NULL) {
num = 0;
}
if (num == 2) {
r = g = b;
} else if (num == 5) {
scale /= 255.f;
r *= scale;
g *= scale;
b *= scale;
} else if (num == 4) {
// Ok, rgb only, no scaling
} else {
gEngine.Con_Printf( "skipping rad entry %s\n", name[0] ? name : "(empty)" );
num = 0;
}
if (num != 0) {
gEngine.Con_Printf("rad entry (%d): %s %f %f %f (%f)\n", num, name, r, g, b, scale);
{
const char *wad_name = NULL;
char *texture_name = Q_strchr(name, '/');
string texname;
int tex_id;
const qboolean enabled = (r != 0 || g != 0 || b != 0);
if (!texture_name) {
texture_name = name;
} else {
// name is now just a wad name
texture_name[0] = '\0';
wad_name = name;
texture_name += 1;
}
// Try bsp texture first
tex_id = lookupTextureF("#%s:%s.mip", map->name, texture_name);
// Try wad texture if bsp is not there
if (!tex_id && wad_name) {
tex_id = lookupTextureF("%s.wad/%s.mip", wad_name, texture_name);
}
if (!tex_id) {
const char *wad = g_light_entities.wadlist;
for (; *wad;) {
const char *const wad_end = Q_strchr(wad, ';');
tex_id = lookupTextureF("%.*s/%s.mip", wad_end - wad, wad, texture_name);
if (tex_id)
break;
wad = wad_end + 1;
}
}
if (tex_id) {
vk_emissive_texture_t *const etex = g_lights.map.emissive_textures + tex_id;
ASSERT(tex_id < MAX_TEXTURES);
etex->emissive[0] = r;
etex->emissive[1] = g;
etex->emissive[2] = b;
etex->set = enabled;
// See DIRECT_SCALE in qrad/lightmap.c
VectorScale(etex->emissive, 0.1f, etex->emissive);
if (!enabled)
gEngine.Con_Reportf("rad entry %s disabled due to zero intensity\n", name);
}
}
}
if (!line_end)
break;
data = line_end + 1;
}
Mem_Free(buffer);
}
static void leafAccumPrepare( void ) {
memset(&g_lights_bsp.accum, 0, sizeof(g_lights_bsp.accum));
}