1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20 //gl_fog.c -- global and volumetric fog
21 
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 
26 #define NH_DEFINE
27 #include "namehack.h"
28 
29 #ifdef HAVE_STRING_H
30 # include <string.h>
31 #endif
32 #ifdef HAVE_STRINGS_H
33 # include <strings.h>
34 #endif
35 
36 #include "QF/cmd.h"
37 #include "QF/qfplist.h"
38 #include "QF/render.h"
39 #include "QF/sys.h"
40 
41 #include "QF/GL/defines.h"
42 #include "QF/GL/funcs.h"
43 
44 #include "compat.h"
45 #include "r_internal.h"
46 
47 //==============================================================================
48 //
49 //  GLOBAL FOG
50 //
51 //==============================================================================
52 
53 static float fog_density;
54 static float fog_red;
55 static float fog_green;
56 static float fog_blue;
57 
58 static float old_density;
59 static float old_red;
60 static float old_green;
61 static float old_blue;
62 
63 static float fade_time; //duration of fade
64 static float fade_done; //time when fade will be done
65 
66 /*
67 	Fog_Update
68 
69 	update internal variables
70 */
71 void
gl_Fog_Update(float density,float red,float green,float blue,float time)72 gl_Fog_Update (float density, float red, float green, float blue, float time)
73 {
74 	//save previous settings for fade
75 	if (time > 0) {
76 		//check for a fade in progress
77 		if (fade_done > vr_data.realtime) {
78 			float       f;
79 
80 			f = (fade_done - vr_data.realtime) / fade_time;
81 			old_density = f * old_density + (1.0 - f) * fog_density;
82 			old_red = f * old_red + (1.0 - f) * fog_red;
83 			old_green = f * old_green + (1.0 - f) * fog_green;
84 			old_blue = f * old_blue + (1.0 - f) * fog_blue;
85 		} else {
86 			old_density = fog_density;
87 			old_red = fog_red;
88 			old_green = fog_green;
89 			old_blue = fog_blue;
90 		}
91 	}
92 
93 	fog_density = density;
94 	fog_red = red;
95 	fog_green = green;
96 	fog_blue = blue;
97 	fade_time = time;
98 	fade_done = vr_data.realtime + time;
99 }
100 
101 /*
102 	Fog_FogCommand_f
103 
104 	handle the 'fog' console command
105 */
106 static void
Fog_FogCommand_f(void)107 Fog_FogCommand_f (void)
108 {
109 	float       density = fog_density;
110 	float       red = fog_red;
111 	float       green = fog_green;
112 	float       blue = fog_blue;
113 	float       time = 0.0;
114 
115 	switch (Cmd_Argc ()) {
116 		default:
117 		case 1:
118 			Sys_Printf ("usage:\n");
119 			Sys_Printf ("   fog <density>\n");
120 			Sys_Printf ("   fog <red> <green> <blue>\n");
121 			Sys_Printf ("   fog <density> <red> <green> <blue>\n");
122 			Sys_Printf ("current values:\n");
123 			Sys_Printf ("   \"density\" is \"%f\"\n", fog_density);
124 			Sys_Printf ("   \"red\" is \"%f\"\n", fog_red);
125 			Sys_Printf ("   \"green\" is \"%f\"\n", fog_green);
126 			Sys_Printf ("   \"blue\" is \"%f\"\n", fog_blue);
127 			return;
128 		case 2:
129 			density = atof (Cmd_Argv(1));
130 			break;
131 		case 3: //TEST
132 			density = atof (Cmd_Argv(1));
133 			time = atof (Cmd_Argv(2));
134 			break;
135 		case 4:
136 			red = atof (Cmd_Argv(1));
137 			green = atof (Cmd_Argv(2));
138 			blue = atof (Cmd_Argv(3));
139 			break;
140 		case 5:
141 			density = atof (Cmd_Argv(1));
142 			red = atof (Cmd_Argv(2));
143 			green = atof (Cmd_Argv(3));
144 			blue = atof (Cmd_Argv(4));
145 			break;
146 		case 6: //TEST
147 			density = atof (Cmd_Argv(1));
148 			red = atof (Cmd_Argv(2));
149 			green = atof (Cmd_Argv(3));
150 			blue = atof (Cmd_Argv(4));
151 			time = atof (Cmd_Argv(5));
152 			break;
153 	}
154 	density = max (0.0, density);
155 	red = bound (0.0, red, 1.0);
156 	green = bound (0.0, green, 1.0);
157 	blue = bound (0.0, blue, 1.0);
158 	gl_Fog_Update (density, red, green, blue, time);
159 }
160 
161 /*
162 	Fog_ParseWorldspawn
163 
164 	called at map load
165 */
166 void
gl_Fog_ParseWorldspawn(plitem_t * worldspawn)167 gl_Fog_ParseWorldspawn (plitem_t *worldspawn)
168 {
169 	plitem_t   *fog;
170 	const char *value;
171 
172 	//initially no fog
173 	fog_density = 0.0;
174 	old_density = 0.0;
175 	fade_time = 0.0;
176 	fade_done = 0.0;
177 
178 	if (!worldspawn)
179 		return; // error
180 	if ((fog = PL_ObjectForKey (worldspawn, "fog"))
181 		&& (value = PL_String (fog))) {
182 		sscanf (value, "%f %f %f %f", &fog_density,
183 				&fog_red, &fog_green, &fog_blue);
184 	}
185 }
186 
187 /*
188 	Fog_GetColor
189 
190 	calculates fog color for this frame, taking into account fade times
191 */
192 float *
gl_Fog_GetColor(void)193 gl_Fog_GetColor (void)
194 {
195 	static float c[4];
196 	float       f;
197 	int         i;
198 
199 	if (fade_done > vr_data.realtime) {
200 		f = (fade_done - vr_data.realtime) / fade_time;
201 		c[0] = f * old_red + (1.0 - f) * fog_red;
202 		c[1] = f * old_green + (1.0 - f) * fog_green;
203 		c[2] = f * old_blue + (1.0 - f) * fog_blue;
204 		c[3] = 1.0;
205 	} else {
206 		c[0] = fog_red;
207 		c[1] = fog_green;
208 		c[2] = fog_blue;
209 		c[3] = 1.0;
210 	}
211 
212 	//find closest 24-bit RGB value, so solid-colored sky can match the fog
213 	//perfectly
214 	for (i = 0; i < 3; i++)
215 		c[i] = (float) (rint (c[i] * 255)) / 255.0f;
216 
217 	return c;
218 }
219 
220 /*
221 	Fog_GetDensity
222 
223 	returns current density of fog
224 */
225 float
gl_Fog_GetDensity(void)226 gl_Fog_GetDensity (void)
227 {
228 	float       f;
229 
230 	if (fade_done > vr_data.realtime) {
231 		f = (fade_done - vr_data.realtime) / fade_time;
232 		return f * old_density + (1.0 - f) * fog_density;
233 	} else {
234 		return fog_density;
235 	}
236 }
237 
238 /*
239 	Fog_SetupFrame
240 
241 	called at the beginning of each frame
242 */
243 void
gl_Fog_SetupFrame(void)244 gl_Fog_SetupFrame (void)
245 {
246 	qfglFogfv (GL_FOG_COLOR, gl_Fog_GetColor ());
247 	qfglFogf (GL_FOG_DENSITY, gl_Fog_GetDensity () / 64.0);
248 }
249 
250 /*
251 	Fog_EnableGFog
252 
253 	called before drawing stuff that should be fogged
254 */
255 void
gl_Fog_EnableGFog(void)256 gl_Fog_EnableGFog (void)
257 {
258 	if (gl_Fog_GetDensity () > 0)
259 		qfglEnable (GL_FOG);
260 }
261 
262 /*
263 	Fog_DisableGFog
264 
265 	called after drawing stuff that should be fogged
266 */
267 void
gl_Fog_DisableGFog(void)268 gl_Fog_DisableGFog (void)
269 {
270 	if (gl_Fog_GetDensity () > 0)
271 		qfglDisable (GL_FOG);
272 }
273 
274 /*
275 	Fog_StartAdditive
276 
277 	called before drawing stuff that is additive blended -- sets fog color
278 	to black
279 */
280 void
gl_Fog_StartAdditive(void)281 gl_Fog_StartAdditive (void)
282 {
283 	vec3_t      color = {0, 0, 0};
284 
285 	if (gl_Fog_GetDensity () > 0)
286 		qfglFogfv (GL_FOG_COLOR, color);
287 }
288 
289 /*
290 	Fog_StopAdditive
291 
292 	called after drawing stuff that is additive blended -- restores fog color
293 */
294 void
gl_Fog_StopAdditive(void)295 gl_Fog_StopAdditive (void)
296 {
297 	if (gl_Fog_GetDensity () > 0)
298 		qfglFogfv (GL_FOG_COLOR, gl_Fog_GetColor ());
299 }
300 
301 //==============================================================================
302 //
303 //  VOLUMETRIC FOG
304 //
305 //==============================================================================
306 
307 //cvar_t r_vfog = {"r_vfog", "1"};
308 
309 //void Fog_DrawVFog (void) {}
310 //void Fog_MarkModels (void) {}
311 
312 //==============================================================================
313 //
314 //  INIT
315 //
316 //==============================================================================
317 
318 /*
319 	Fog_NewMap
320 
321 	called whenever a map is loaded
322 */
323 #if 0
324 void
325 gl_Fog_NewMap (void)
326 {
327 	Fog_ParseWorldspawn (); //for global fog
328 	Fog_MarkModels (); //for volumetric fog
329 }
330 #endif
331 
332 /*
333 	Fog_Init
334 
335 	called when quake initializes
336 */
337 void
gl_Fog_Init(void)338 gl_Fog_Init (void)
339 {
340 	Cmd_AddCommand ("fog", Fog_FogCommand_f, "");
341 
342 	//Cvar_RegisterVariable (&r_vfog, NULL);
343 
344 	//set up global fog
345 	fog_density = 0.0;
346 	fog_red = 0.3;
347 	fog_green = 0.3;
348 	fog_blue = 0.3;
349 
350 	qfglFogi (GL_FOG_MODE, GL_EXP2);
351 }
352