mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2025-02-09 01:01:07 +00:00
max() macro forces double read of its arguments, so MSG_ReadShort()
was being called twice, therefore it has always been broken since
more than 20 years, and not to mention its definition change going
from fitzquake v0.60 to v0.65. Darkplaces svn r1778 changelog says:
"minor cleaning of obsolete protocol stuff (svc_fog is now considered unused, because it really never was used)"
http://svn.icculus.org/twilight?view=rev&revision=1778
524e813007
FTEQW does it right by doing a single message read (svcfitz_fog)
We now do a single message read like FTEQW, as it should have been.
svc_fog message has probably never been emited by any mod's qc, so
no worries.
411 lines
8.2 KiB
C
411 lines
8.2 KiB
C
/*
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
|
Copyright (C) 2007-2008 Kristian Duske
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
//gl_fog.c -- global and volumetric fog
|
|
|
|
#include "quakedef.h"
|
|
|
|
//==============================================================================
|
|
//
|
|
// GLOBAL FOG
|
|
//
|
|
//==============================================================================
|
|
|
|
#define DEFAULT_DENSITY 0.0
|
|
#define DEFAULT_GRAY 0.3
|
|
|
|
float fog_density;
|
|
float fog_red;
|
|
float fog_green;
|
|
float fog_blue;
|
|
|
|
float old_density;
|
|
float old_red;
|
|
float old_green;
|
|
float old_blue;
|
|
|
|
float fade_time; //duration of fade
|
|
float fade_done; //time when fade will be done
|
|
|
|
/*
|
|
=============
|
|
Fog_Update
|
|
|
|
update internal variables
|
|
=============
|
|
*/
|
|
void Fog_Update (float density, float red, float green, float blue, float time)
|
|
{
|
|
//save previous settings for fade
|
|
if (time > 0)
|
|
{
|
|
//check for a fade in progress
|
|
if (fade_done > cl.time)
|
|
{
|
|
float f;
|
|
|
|
f = (fade_done - cl.time) / fade_time;
|
|
old_density = f * old_density + (1.0 - f) * fog_density;
|
|
old_red = f * old_red + (1.0 - f) * fog_red;
|
|
old_green = f * old_green + (1.0 - f) * fog_green;
|
|
old_blue = f * old_blue + (1.0 - f) * fog_blue;
|
|
}
|
|
else
|
|
{
|
|
old_density = fog_density;
|
|
old_red = fog_red;
|
|
old_green = fog_green;
|
|
old_blue = fog_blue;
|
|
}
|
|
}
|
|
|
|
fog_density = density;
|
|
fog_red = red;
|
|
fog_green = green;
|
|
fog_blue = blue;
|
|
fade_time = time;
|
|
fade_done = cl.time + time;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_ParseServerMessage
|
|
|
|
handle an SVC_FOG message from server
|
|
=============
|
|
*/
|
|
void Fog_ParseServerMessage (void)
|
|
{
|
|
float density, red, green, blue, time;
|
|
|
|
density = MSG_ReadByte() / 255.0;
|
|
red = MSG_ReadByte() / 255.0;
|
|
green = MSG_ReadByte() / 255.0;
|
|
blue = MSG_ReadByte() / 255.0;
|
|
time = MSG_ReadShort() / 100.0;
|
|
if (time < 0.0f) time = 0.0f;
|
|
|
|
Fog_Update (density, red, green, blue, time);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_FogCommand_f
|
|
|
|
handle the 'fog' console command
|
|
=============
|
|
*/
|
|
void Fog_FogCommand_f (void)
|
|
{
|
|
switch (Cmd_Argc())
|
|
{
|
|
default:
|
|
case 1:
|
|
Con_Printf("usage:\n");
|
|
Con_Printf(" fog <density>\n");
|
|
Con_Printf(" fog <red> <green> <blue>\n");
|
|
Con_Printf(" fog <density> <red> <green> <blue>\n");
|
|
Con_Printf("current values:\n");
|
|
Con_Printf(" \"density\" is \"%f\"\n", fog_density);
|
|
Con_Printf(" \"red\" is \"%f\"\n", fog_red);
|
|
Con_Printf(" \"green\" is \"%f\"\n", fog_green);
|
|
Con_Printf(" \"blue\" is \"%f\"\n", fog_blue);
|
|
break;
|
|
case 2:
|
|
Fog_Update(q_max(0.0, atof(Cmd_Argv(1))),
|
|
fog_red,
|
|
fog_green,
|
|
fog_blue,
|
|
0.0);
|
|
break;
|
|
case 3: //TEST
|
|
Fog_Update(q_max(0.0, atof(Cmd_Argv(1))),
|
|
fog_red,
|
|
fog_green,
|
|
fog_blue,
|
|
atof(Cmd_Argv(2)));
|
|
break;
|
|
case 4:
|
|
Fog_Update(fog_density,
|
|
CLAMP(0.0, atof(Cmd_Argv(1)), 1.0),
|
|
CLAMP(0.0, atof(Cmd_Argv(2)), 1.0),
|
|
CLAMP(0.0, atof(Cmd_Argv(3)), 1.0),
|
|
0.0);
|
|
break;
|
|
case 5:
|
|
Fog_Update(q_max(0.0, atof(Cmd_Argv(1))),
|
|
CLAMP(0.0, atof(Cmd_Argv(2)), 1.0),
|
|
CLAMP(0.0, atof(Cmd_Argv(3)), 1.0),
|
|
CLAMP(0.0, atof(Cmd_Argv(4)), 1.0),
|
|
0.0);
|
|
break;
|
|
case 6: //TEST
|
|
Fog_Update(q_max(0.0, atof(Cmd_Argv(1))),
|
|
CLAMP(0.0, atof(Cmd_Argv(2)), 1.0),
|
|
CLAMP(0.0, atof(Cmd_Argv(3)), 1.0),
|
|
CLAMP(0.0, atof(Cmd_Argv(4)), 1.0),
|
|
atof(Cmd_Argv(5)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_ParseWorldspawn
|
|
|
|
called at map load
|
|
=============
|
|
*/
|
|
void Fog_ParseWorldspawn (void)
|
|
{
|
|
char key[128], value[4096];
|
|
const char *data;
|
|
|
|
//initially no fog
|
|
fog_density = DEFAULT_DENSITY;
|
|
fog_red = DEFAULT_GRAY;
|
|
fog_green = DEFAULT_GRAY;
|
|
fog_blue = DEFAULT_GRAY;
|
|
|
|
old_density = DEFAULT_DENSITY;
|
|
old_red = DEFAULT_GRAY;
|
|
old_green = DEFAULT_GRAY;
|
|
old_blue = DEFAULT_GRAY;
|
|
|
|
fade_time = 0.0;
|
|
fade_done = 0.0;
|
|
|
|
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] == '_')
|
|
q_strlcpy(key, com_token + 1, sizeof(key));
|
|
else
|
|
q_strlcpy(key, com_token, sizeof(key));
|
|
while (key[0] && key[strlen(key)-1] == ' ') // remove trailing spaces
|
|
key[strlen(key)-1] = 0;
|
|
data = COM_Parse(data);
|
|
if (!data)
|
|
return; // error
|
|
q_strlcpy(value, com_token, sizeof(value));
|
|
|
|
if (!strcmp("fog", key))
|
|
{
|
|
sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_GetColor
|
|
|
|
calculates fog color for this frame, taking into account fade times
|
|
=============
|
|
*/
|
|
float *Fog_GetColor (void)
|
|
{
|
|
static float c[4];
|
|
float f;
|
|
int i;
|
|
|
|
if (fade_done > cl.time)
|
|
{
|
|
f = (fade_done - cl.time) / fade_time;
|
|
c[0] = f * old_red + (1.0 - f) * fog_red;
|
|
c[1] = f * old_green + (1.0 - f) * fog_green;
|
|
c[2] = f * old_blue + (1.0 - f) * fog_blue;
|
|
c[3] = 1.0;
|
|
}
|
|
else
|
|
{
|
|
c[0] = fog_red;
|
|
c[1] = fog_green;
|
|
c[2] = fog_blue;
|
|
c[3] = 1.0;
|
|
}
|
|
|
|
//find closest 24-bit RGB value, so solid-colored sky can match the fog perfectly
|
|
for (i=0;i<3;i++)
|
|
c[i] = (float)(Q_rint(c[i] * 255)) / 255.0f;
|
|
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_GetDensity
|
|
|
|
returns current density of fog
|
|
=============
|
|
*/
|
|
float Fog_GetDensity (void)
|
|
{
|
|
float f;
|
|
|
|
if (fade_done > cl.time)
|
|
{
|
|
f = (fade_done - cl.time) / fade_time;
|
|
return f * old_density + (1.0 - f) * fog_density;
|
|
}
|
|
else
|
|
return fog_density;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_SetupFrame
|
|
|
|
called at the beginning of each frame
|
|
=============
|
|
*/
|
|
void Fog_SetupFrame (void)
|
|
{
|
|
glFogfv(GL_FOG_COLOR, Fog_GetColor());
|
|
glFogf(GL_FOG_DENSITY, Fog_GetDensity() / 64.0);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_EnableGFog
|
|
|
|
called before drawing stuff that should be fogged
|
|
=============
|
|
*/
|
|
void Fog_EnableGFog (void)
|
|
{
|
|
if (Fog_GetDensity() > 0)
|
|
glEnable(GL_FOG);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_DisableGFog
|
|
|
|
called after drawing stuff that should be fogged
|
|
=============
|
|
*/
|
|
void Fog_DisableGFog (void)
|
|
{
|
|
if (Fog_GetDensity() > 0)
|
|
glDisable(GL_FOG);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_StartAdditive
|
|
|
|
called before drawing stuff that is additive blended -- sets fog color to black
|
|
=============
|
|
*/
|
|
void Fog_StartAdditive (void)
|
|
{
|
|
vec3_t color = {0,0,0};
|
|
|
|
if (Fog_GetDensity() > 0)
|
|
glFogfv(GL_FOG_COLOR, color);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_StopAdditive
|
|
|
|
called after drawing stuff that is additive blended -- restores fog color
|
|
=============
|
|
*/
|
|
void Fog_StopAdditive (void)
|
|
{
|
|
if (Fog_GetDensity() > 0)
|
|
glFogfv(GL_FOG_COLOR, Fog_GetColor());
|
|
}
|
|
|
|
//==============================================================================
|
|
//
|
|
// VOLUMETRIC FOG
|
|
//
|
|
//==============================================================================
|
|
|
|
cvar_t r_vfog = {"r_vfog", "1", CVAR_NONE};
|
|
|
|
void Fog_DrawVFog (void){}
|
|
void Fog_MarkModels (void){}
|
|
|
|
//==============================================================================
|
|
//
|
|
// INIT
|
|
//
|
|
//==============================================================================
|
|
|
|
/*
|
|
=============
|
|
Fog_NewMap
|
|
|
|
called whenever a map is loaded
|
|
=============
|
|
*/
|
|
void Fog_NewMap (void)
|
|
{
|
|
Fog_ParseWorldspawn (); //for global fog
|
|
Fog_MarkModels (); //for volumetric fog
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_Init
|
|
|
|
called when quake initializes
|
|
=============
|
|
*/
|
|
void Fog_Init (void)
|
|
{
|
|
Cmd_AddCommand ("fog",Fog_FogCommand_f);
|
|
|
|
//Cvar_RegisterVariable (&r_vfog);
|
|
|
|
//set up global fog
|
|
fog_density = DEFAULT_DENSITY;
|
|
fog_red = DEFAULT_GRAY;
|
|
fog_green = DEFAULT_GRAY;
|
|
fog_blue = DEFAULT_GRAY;
|
|
|
|
Fog_SetupState ();
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Fog_SetupState
|
|
|
|
ericw -- moved from Fog_Init, state that needs to be setup when a new context is created
|
|
=============
|
|
*/
|
|
void Fog_SetupState (void)
|
|
{
|
|
glFogi(GL_FOG_MODE, GL_EXP2);
|
|
}
|