From 01faf4e5b6149eeed8f35d6a1f04e88af5a473bc Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Sun, 26 Jul 2015 21:51:25 +0000 Subject: [PATCH] new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine) new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm) The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default. The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog". see also: http://forums.insideqc.com/viewtopic.php?f=3&t=5532 http://celephais.net/board/view_thread.php?id=60452&start=937 git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd --- Quake/gl_model.c | 10 ++++ Quake/gl_model.h | 4 ++ Quake/gl_rmain.c | 6 +++ Quake/gl_rmisc.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++ Quake/gl_sky.c | 28 +++++++++-- Quake/glquake.h | 7 +++ Quake/r_brush.c | 2 +- Quake/r_world.c | 34 +++++++++---- 8 files changed, 197 insertions(+), 15 deletions(-) diff --git a/Quake/gl_model.c b/Quake/gl_model.c index dedeaefa..c99516ed 100644 --- a/Quake/gl_model.c +++ b/Quake/gl_model.c @@ -1193,6 +1193,16 @@ void Mod_LoadFaces (lump_t *l, qboolean bsp2) else if (out->texinfo->texture->name[0] == '*') // warp surface { out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + + // detect special liquid types + if (!strncmp (out->texinfo->texture->name, "*lava", 5)) + out->flags |= SURF_DRAWLAVA; + else if (!strncmp (out->texinfo->texture->name, "*slime", 6)) + out->flags |= SURF_DRAWSLIME; + else if (!strncmp (out->texinfo->texture->name, "*tele", 5)) + out->flags |= SURF_DRAWTELE; + else out->flags |= SURF_DRAWWATER; + Mod_PolyForUnlitSurface (out); GL_SubdivideSurface (out); } diff --git a/Quake/gl_model.h b/Quake/gl_model.h index 023e4847..0c017ad3 100644 --- a/Quake/gl_model.h +++ b/Quake/gl_model.h @@ -108,6 +108,10 @@ typedef struct texture_s #define SURF_UNDERWATER 0x80 #define SURF_NOTEXTURE 0x100 //johnfitz #define SURF_DRAWFENCE 0x200 +#define SURF_DRAWLAVA 0x400 +#define SURF_DRAWSLIME 0x800 +#define SURF_DRAWTELE 0x1000 +#define SURF_DRAWWATER 0x2000 // !!! if this is changed, it must be changed in asm_draw.h too !!! typedef struct diff --git a/Quake/gl_rmain.c b/Quake/gl_rmain.c index 1016533b..5869030f 100644 --- a/Quake/gl_rmain.c +++ b/Quake/gl_rmain.c @@ -103,6 +103,12 @@ extern cvar_t r_vfog; cvar_t gl_zfix = {"gl_zfix", "0", CVAR_NONE}; // QuakeSpasm z-fighting fix +cvar_t r_lavaalpha = {"r_lavaalpha","0",CVAR_NONE}; +cvar_t r_telealpha = {"r_telealpha","0",CVAR_NONE}; +cvar_t r_slimealpha = {"r_slimealpha","0",CVAR_NONE}; + +float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; + qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz //============================================================================== diff --git a/Quake/gl_rmisc.c b/Quake/gl_rmisc.c index cc78233b..3630bae0 100644 --- a/Quake/gl_rmisc.c +++ b/Quake/gl_rmisc.c @@ -109,6 +109,64 @@ static void R_Model_ExtraFlags_List_f (cvar_t *var) Mod_SetExtraFlags (cl.model_precache[i]); } +/* +==================== +R_SetWateralpha_f -- ericw +==================== +*/ +static void R_SetWateralpha_f (cvar_t *var) +{ + map_wateralpha = var->value; +} + +/* +==================== +R_SetLavaalpha_f -- ericw +==================== +*/ +static void R_SetLavaalpha_f (cvar_t *var) +{ + map_lavaalpha = var->value; +} + +/* +==================== +R_SetTelealpha_f -- ericw +==================== +*/ +static void R_SetTelealpha_f (cvar_t *var) +{ + map_telealpha = var->value; +} + +/* +==================== +R_SetSlimealpha_f -- ericw +==================== +*/ +static void R_SetSlimealpha_f (cvar_t *var) +{ + map_slimealpha = var->value; +} + +/* +==================== +GL_WaterAlphaForSurfface -- ericw +==================== +*/ +float GL_WaterAlphaForSurface (msurface_t *fa) +{ + if (fa->flags & SURF_DRAWLAVA) + return map_lavaalpha > 0 ? map_lavaalpha : map_wateralpha; + else if (fa->flags & SURF_DRAWTELE) + return map_telealpha > 0 ? map_telealpha : map_wateralpha; + else if (fa->flags & SURF_DRAWSLIME) + return map_slimealpha > 0 ? map_slimealpha : map_wateralpha; + else + return map_wateralpha; +} + + /* =============== R_Init @@ -128,6 +186,7 @@ void R_Init (void) Cvar_RegisterVariable (&r_drawviewmodel); Cvar_RegisterVariable (&r_shadows); Cvar_RegisterVariable (&r_wateralpha); + Cvar_SetCallback (&r_wateralpha, R_SetWateralpha_f); Cvar_RegisterVariable (&r_dynamic); Cvar_RegisterVariable (&r_novis); Cvar_SetCallback (&r_novis, R_VisChanged); @@ -173,6 +232,12 @@ void R_Init (void) //johnfitz Cvar_RegisterVariable (&gl_zfix); // QuakeSpasm z-fighting fix + Cvar_RegisterVariable (&r_lavaalpha); + Cvar_RegisterVariable (&r_telealpha); + Cvar_RegisterVariable (&r_slimealpha); + Cvar_SetCallback (&r_lavaalpha, R_SetLavaalpha_f); + Cvar_SetCallback (&r_telealpha, R_SetTelealpha_f); + Cvar_SetCallback (&r_slimealpha, R_SetSlimealpha_f); R_InitParticles (); R_SetClearColor_f (&r_clearcolor); //johnfitz @@ -255,6 +320,61 @@ void R_NewGame (void) playertextures[i] = NULL; } +/* +============= +R_ParseWorldspawn + +called at map load +============= +*/ +static void R_ParseWorldspawn (void) +{ + char key[128], value[4096]; + const char *data; + + map_wateralpha = r_wateralpha.value; + map_lavaalpha = r_lavaalpha.value; + map_telealpha = r_telealpha.value; + map_slimealpha = r_slimealpha.value; + + data = COM_Parse(cl.worldmodel->entities); + if (!data) + return; // error + if (com_token[0] != '{') + return; // error + while (1) + { + data = COM_Parse(data); + if (!data) + return; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strcpy(key, com_token + 1); + else + strcpy(key, com_token); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + data = COM_Parse(data); + if (!data) + return; // error + strcpy(value, com_token); + + if (!strcmp("wateralpha", key)) + map_wateralpha = atof(value); + + if (!strcmp("lavaalpha", key)) + map_lavaalpha = atof(value); + + if (!strcmp("telealpha", key)) + map_telealpha = atof(value); + + if (!strcmp("slimealpha", key)) + map_slimealpha = atof(value); + } +} + + /* =============== R_NewMap @@ -284,6 +404,7 @@ void R_NewMap (void) Sky_NewMap (); //johnfitz -- skybox in worldspawn Fog_NewMap (); //johnfitz -- global fog in worldspawn + R_ParseWorldspawn (); //ericw -- wateralpha, lavaalpha, telealpha, slimealpha in worldspawn load_subdivide_size = gl_subdivide_size.value; //johnfitz -- is this the right place to set this? } diff --git a/Quake/gl_sky.c b/Quake/gl_sky.c index a97748eb..7c9cf639 100644 --- a/Quake/gl_sky.c +++ b/Quake/gl_sky.c @@ -77,6 +77,8 @@ int vec_to_st[6][3] = {-2,1,-3} }; +float skyfog; // ericw + //============================================================================== // // INIT @@ -223,6 +225,7 @@ void Sky_NewMap (void) skybox_name[0] = 0; for (i=0; i<6; i++) skybox_textures[i] = NULL; + skyfog = r_skyfog.value; // // read worldspawn (this is so ugly, and shouldn't it be done on the server?) @@ -258,6 +261,9 @@ void Sky_NewMap (void) if (!strcmp("sky", key)) Sky_LoadSkyBox(value); + if (!strcmp("skyfog", key)) + skyfog = atof(value); + #if 1 //also accept non-standard keys else if (!strcmp("skyname", key)) //half-life Sky_LoadSkyBox(value); @@ -287,6 +293,17 @@ void Sky_SkyCommand_f (void) } } +/* +==================== +R_SetSkyfog_f -- ericw +==================== +*/ +static void R_SetSkyfog_f (cvar_t *var) +{ +// clear any skyfog setting from worldspawn + skyfog = var->value; +} + /* ============= Sky_Init @@ -300,6 +317,7 @@ void Sky_Init (void) Cvar_RegisterVariable (&r_sky_quality); Cvar_RegisterVariable (&r_skyalpha); Cvar_RegisterVariable (&r_skyfog); + Cvar_SetCallback (&r_skyfog, R_SetSkyfog_f); Cmd_AddCommand ("sky",Sky_SkyCommand_f); @@ -699,14 +717,14 @@ void Sky_DrawSkyBox (void) rs_skypolys++; rs_skypasses++; - if (Fog_GetDensity() > 0 && r_skyfog.value > 0) + if (Fog_GetDensity() > 0 && skyfog > 0) { float *c; c = Fog_GetColor(); glEnable (GL_BLEND); glDisable (GL_TEXTURE_2D); - glColor4f (c[0],c[1],c[2], CLAMP(0.0,r_skyfog.value,1.0)); + glColor4f (c[0],c[1],c[2], CLAMP(0.0,skyfog,1.0)); glBegin (GL_QUADS); Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i); @@ -850,14 +868,14 @@ void Sky_DrawFaceQuad (glpoly_t *p) rs_skypasses += 2; } - if (Fog_GetDensity() > 0 && r_skyfog.value > 0) + if (Fog_GetDensity() > 0 && skyfog > 0) { float *c; c = Fog_GetColor(); glEnable (GL_BLEND); glDisable (GL_TEXTURE_2D); - glColor4f (c[0],c[1],c[2], CLAMP(0.0,r_skyfog.value,1.0)); + glColor4f (c[0],c[1],c[2], CLAMP(0.0,skyfog,1.0)); glBegin (GL_QUADS); for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) @@ -993,7 +1011,7 @@ void Sky_DrawSky (void) // // render slow sky: cloud layers or skybox // - if (!r_fastsky.value && !(Fog_GetDensity() > 0 && r_skyfog.value >= 1)) + if (!r_fastsky.value && !(Fog_GetDensity() > 0 && skyfog >= 1)) { glDepthFunc(GL_GEQUAL); glDepthMask(0); diff --git a/Quake/glquake.h b/Quake/glquake.h index 3715eb23..6a8480e4 100644 --- a/Quake/glquake.h +++ b/Quake/glquake.h @@ -132,6 +132,9 @@ extern cvar_t r_fullbright; extern cvar_t r_lightmap; extern cvar_t r_shadows; extern cvar_t r_wateralpha; +extern cvar_t r_lavaalpha; +extern cvar_t r_telealpha; +extern cvar_t r_slimealpha; extern cvar_t r_dynamic; extern cvar_t r_novis; @@ -296,6 +299,8 @@ typedef struct glsl_attrib_binding_s { GLuint attrib; } glsl_attrib_binding_t; +extern float map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha; //ericw + //johnfitz -- fog functions called from outside gl_fog.c void Fog_ParseServerMessage (void); float *Fog_GetColor (void); @@ -383,5 +388,7 @@ void GL_ClearBufferBindings (); void GLSLGamma_DeleteTexture (void); void GLSLGamma_GammaCorrect (void); +float GL_WaterAlphaForSurface (msurface_t *fa); + #endif /* __GLQUAKE_H */ diff --git a/Quake/r_brush.c b/Quake/r_brush.c index c4d8daa1..e12fb4ef 100644 --- a/Quake/r_brush.c +++ b/Quake/r_brush.c @@ -248,7 +248,7 @@ void R_DrawSequentialPoly (msurface_t *s) if (s->flags & SURF_DRAWTURB) { if (currententity->alpha == ENTALPHA_DEFAULT) - entalpha = CLAMP(0.0,r_wateralpha.value,1.0); + entalpha = CLAMP(0.0, GL_WaterAlphaForSurface(s), 1.0); if (entalpha < 1) { diff --git a/Quake/r_world.c b/Quake/r_world.c index 05adceac..95e957e2 100644 --- a/Quake/r_world.c +++ b/Quake/r_world.c @@ -636,6 +636,23 @@ void R_DrawTextureChains_TextureOnly (qmodel_t *model, entity_t *ent, texchain_t } } +/* +================ +GL_WaterAlphaForEntitySurface -- ericw + +Returns the water alpha to use for the entity and surface combination. +================ +*/ +float GL_WaterAlphaForEntitySurface (entity_t *ent, msurface_t *s) +{ + float entalpha; + if (ent == NULL || ent->alpha == ENTALPHA_DEFAULT) + entalpha = GL_WaterAlphaForSurface(s); + else + entalpha = ENTALPHA_DECODE(ent->alpha); + return entalpha; +} + /* ================ R_DrawTextureChains_Water -- johnfitz @@ -653,13 +670,6 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) // ericw -- !r_drawworld_cheatsafe check moved to R_DrawWorld_Water () return; - if (ent == NULL || ent->alpha == ENTALPHA_DEFAULT) - entalpha = r_wateralpha.value; - else - entalpha = ENTALPHA_DECODE(ent->alpha); - - R_BeginTransparentDrawing (entalpha); - if (r_oldwater.value) { for (i=0 ; inumtextures ; i++) @@ -668,11 +678,14 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB)) continue; bound = false; + entalpha = 1.0f; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { + entalpha = GL_WaterAlphaForEntitySurface (ent, s); + R_BeginTransparentDrawing (entalpha); GL_Bind (t->gltexture); bound = true; } @@ -682,6 +695,7 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain rs_brushpasses++; } } + R_EndTransparentDrawing (entalpha); } } else @@ -692,11 +706,14 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB)) continue; bound = false; + entalpha = 1.0f; for (s = t->texturechains[chain]; s; s = s->texturechain) if (!s->culled) { if (!bound) //only bind once we are sure we need this texture { + entalpha = GL_WaterAlphaForEntitySurface (ent, s); + R_BeginTransparentDrawing (entalpha); GL_Bind (t->warpimage); if (model != cl.worldmodel) @@ -712,10 +729,9 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain DrawGLPoly (s->polys); rs_brushpasses++; } + R_EndTransparentDrawing (entalpha); } } - - R_EndTransparentDrawing (entalpha); } /*