From af661232e315ba074b6aa2ba2c9c7b5c65b2557b Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 6 Jul 2021 00:12:35 +0000 Subject: [PATCH] Support for equirectangular sky images. Because skybox orientations are generally too hard to get right. Urgh. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5955 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/image.c | 94 +++++++++++++++++++++-------- engine/client/m_options.c | 20 ++++-- engine/gl/gl_warp.c | 31 +++++++++- engine/shaders/glsl/defaultsky.glsl | 12 ++++ 4 files changed, 124 insertions(+), 33 deletions(-) diff --git a/engine/client/image.c b/engine/client/image.c index a8af5cb48..1cc918d4d 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -3505,12 +3505,13 @@ static qbyte *ReadPBMFile(qbyte *buf, size_t len, const char *fname, int *width, static void *ReadRadianceFile(qbyte *buf, size_t len, const char *fname, int *width, int *height, uploadfmt_t *format) { //this isn't expected to be fast. qbyte *end = buf+len; - size_t l, x, y, w, h; + size_t l, x, y, w, h, e; float *r, *o, m; qbyte rgbe[4]; char fmt[128]; char line[256]; + byte_vec4_t *row = NULL; w = h = 0; *fmt = 0; while (buf < end) @@ -3535,13 +3536,13 @@ static void *ReadRadianceFile(qbyte *buf, size_t len, const char *fname, int *wi Con_Printf("%s uses unsupported orientation\n", fname); return NULL; } - w = strtol(buf+3, (char**)&buf, 0); + h = strtol(buf+3, (char**)&buf, 0); if (strncmp(buf, " +X ", 4)) { Con_Printf("%s uses unsupported orientation\n", fname); return NULL; } - h = strtol(buf+4, (char**)&buf, 0); + w = strtol(buf+4, (char**)&buf, 0); if (*buf == '\r') buf++; if (*buf++ != '\n') @@ -3556,38 +3557,83 @@ static void *ReadRadianceFile(qbyte *buf, size_t len, const char *fname, int *wi r = o = BZ_Malloc(sizeof(float)*4*w*h); if (!r) return NULL; - for (y=0; y < h; y++) + for (y=0; y < h && buf+4= end) + goto fail; + if (*buf > 128) + { + e = x + (*buf++ - 128); + v = *buf++; + if (e == x || e > w) + goto fail; + while (x < e) + row[x++][c] = v; + } + else + { + e = x + *buf++; + if (e == x || e > w || buf+(e-x) >= end) + goto fail; + while (x < e) + row[x++][c] = *buf++; + } + } } - m = ldexp(1,rgbe[3]-136); - *o++ = m * rgbe[0]; - *o++ = m * rgbe[1]; - *o++ = m * rgbe[2]; - *o++ = 1; + //decompressed the entire line, can make sense of it now. + for (x=0; x < w; x++) + { + m = ldexp(1,row[x][3]-136); + *o++ = m * row[x][0]; + *o++ = m * row[x][1]; + *o++ = m * row[x][2]; + *o++ = 1; + } + } + else if (rgbe[0] == 1 && rgbe[1] == 1 && rgbe[2] == 1) + { //old rle logic + Con_Printf("%s uses unsupported (old) RLE compression\n", fname); + goto fail; + } + else + { + for (x=0; x < w && buf+4= 1\n" - "{\n" //fake it anyway. - "set r_shadow_realtime_dlight 1\n" - "set r_shadow_realtime_dlight_shadows 0\n" - "set r_dynamic 0\n" - "}\n" "set r_temporalscenecache 1\n" //the main speedup. "set r_lightstylespeed 0\n" //FIXME: we shouldn't need this, but its too stuttery without. "set sv_autooffload 1\n" //Needs polish still. "set gl_pbolightmaps 1\n" //FIXME: this needs to be the default eventually. }, + { "dm", + "Various settings to make you more competitive." + + "set cl_yieldcpu 0\n" + "set v_kickroll 0\n" //roll change when taking damage + "set v_kickpitch 0\n" //pitch change when taking damage + "set v_damagecshift 0\n" //colour change when taking damage + "set v_gunkick 0\n" //recoil when firing + "set cl_rollangle 0\n" //rolling when strafing + "set cl_bob 0\n" //view bobbing when moving. +#ifdef _WIN32 + "set sys_clockprecision 1\n" //windows kinda sucks otherwise +#endif + }, { "qw", "Enable QuakeWorld-isms, for better gameplay.", diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index 09ecb1857..94172bbd9 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -79,22 +79,47 @@ void R_SetSky(const char *sky) shadername = va("skybox_%s", sky); if (!forcedsky || strcmp(shadername, forcedsky->name)) { + texnums_t tex; forcedsky = NULL; //fall back to regular skies if forcing fails. if (!*sky) return; //no need to do anything + memset(&tex, 0, sizeof(tex)); + + tex.base = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_NOMIPMAP); + if (tex.reflectcube && tex.reflectcube->status == TEX_LOADING) + COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING); + if (tex.base->width && TEXLOADED(tex.base)) + { + forcedsky = R_RegisterShader(shadername, 0, + "{\n" + "sort sky\n" + "program defaultsky#EQUI\n" + "{\n" + "if !$unmaskedsky\n" /* Q2/HL require the skybox to not draw over geometry, shouldn't we force it? --eukara */ + "depthwrite\n" + "endif\n" + "map \"$diffuse\"\n" + "tcgen skybox\n" + "}\n" + "surfaceparm nodlight\n" + "surfaceparm sky\n" + "}"); + R_BuildDefaultTexnums(&tex, forcedsky, IF_WORLDTEX); + return; + } + //if we have cubemaps then we can just go and use a cubemap for our skybox if (sh_config.havecubemaps) { - texnums_t tex; memset(&tex, 0, sizeof(tex)); - tex.reflectcube = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_TEXTYPE_CUBE|IF_CLAMP); + tex.reflectcube = R_LoadHiResTexture(sky, "env:gfx/env", IF_LOADNOW|IF_TEXTYPE_CUBE|IF_NOMIPMAP|IF_CLAMP); if (tex.reflectcube && tex.reflectcube->status == TEX_LOADING) COM_WorkerPartialSync(tex.reflectcube, &tex.reflectcube->status, TEX_LOADING); if (tex.reflectcube->width && TEXLOADED(tex.reflectcube)) { - forcedsky = R_RegisterShader(va("skybox_%s", sky), 0, + forcedsky = R_RegisterShader(shadername, 0, "{\n" "sort sky\n" "program defaultskybox\n" diff --git a/engine/shaders/glsl/defaultsky.glsl b/engine/shaders/glsl/defaultsky.glsl index b1248e75e..e9c21203b 100644 --- a/engine/shaders/glsl/defaultsky.glsl +++ b/engine/shaders/glsl/defaultsky.glsl @@ -22,6 +22,16 @@ void main () { vec2 tccoord; vec3 dir = pos - e_eyepos; + +#ifdef EQUI +#define PI 3.1415926535897932384626433832795 + dir = normalize(dir); + tccoord.x = atan(dir.x,dir.y) / (PI*2.0) + 0.5; + tccoord.y = acos(dir.z) / PI; + + vec3 sky = vec3(texture2D(s_base, tccoord)); +#else + dir.z *= 3.0; dir.xy /= 0.5*length(dir); tccoord = (dir.xy + e_time*0.03125); @@ -29,6 +39,8 @@ void main () tccoord = (dir.xy + e_time*0.0625); vec4 clouds = texture2D(s_cloud, tccoord); sky = (sky.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb); +#endif + #ifdef FOG sky.rgb = mix(sky.rgb, w_fogcolour, float(r_skyfog)*w_fogalpha); //flat fog ignoring actual geometry //sky = fog3(sky); //fog according to actual geometry