diff --git a/quakespasm/Quake/gl_model.c b/quakespasm/Quake/gl_model.c index dedeaefa..c99516ed 100644 --- a/quakespasm/Quake/gl_model.c +++ b/quakespasm/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/quakespasm/Quake/gl_model.h b/quakespasm/Quake/gl_model.h index 023e4847..0c017ad3 100644 --- a/quakespasm/Quake/gl_model.h +++ b/quakespasm/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/quakespasm/Quake/gl_rmain.c b/quakespasm/Quake/gl_rmain.c index 1016533b..5869030f 100644 --- a/quakespasm/Quake/gl_rmain.c +++ b/quakespasm/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/quakespasm/Quake/gl_rmisc.c b/quakespasm/Quake/gl_rmisc.c index cc78233b..3630bae0 100644 --- a/quakespasm/Quake/gl_rmisc.c +++ b/quakespasm/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/quakespasm/Quake/gl_sky.c b/quakespasm/Quake/gl_sky.c index a97748eb..7c9cf639 100644 --- a/quakespasm/Quake/gl_sky.c +++ b/quakespasm/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/quakespasm/Quake/glquake.h b/quakespasm/Quake/glquake.h index 3715eb23..6a8480e4 100644 --- a/quakespasm/Quake/glquake.h +++ b/quakespasm/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/quakespasm/Quake/r_brush.c b/quakespasm/Quake/r_brush.c index c4d8daa1..e12fb4ef 100644 --- a/quakespasm/Quake/r_brush.c +++ b/quakespasm/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/quakespasm/Quake/r_world.c b/quakespasm/Quake/r_world.c index 05adceac..95e957e2 100644 --- a/quakespasm/Quake/r_world.c +++ b/quakespasm/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); } /*