1 /*
2  * Copyright (C) 1997-2001 Id Software, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2 of the License, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 59
17  * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 #include "gl_local.h"
21 
22 int		r_numflares;
23 flare_t		*r_flares[MAX_FLARES];
24 
25 void
R_RenderFlares(void)26 R_RenderFlares(void)
27 {
28 	int		i;
29 
30 	if (gl_flares->value == 0)
31 		return;
32 
33 	qglDepthMask(0);
34 	qglDisable(GL_TEXTURE_2D);
35 	qglShadeModel(GL_SMOOTH);
36 	qglEnable(GL_BLEND);
37 
38 	/* Fog bug fix by Kirk Barnes. */
39 	qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
40 
41 	for (i = 0; i < r_numflares; i++)
42 		if (ri.CL_IsVisible(r_origin, r_flares[i]->origin))
43 			R_RenderFlare(r_flares[i]);
44 
45 	qglColor3f(1, 1, 1);
46 	qglDisable(GL_BLEND);
47 	qglEnable(GL_TEXTURE_2D);
48 	qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
49 	qglDepthMask(1);
50 }
51 
52 void
R_RenderFlare(flare_t * light)53 R_RenderFlare(flare_t *light)
54 {
55 	char		pathname[MAX_QPATH];	/* Flare image path. */
56 	int		size;			/* Flare size. */
57 	int		style;			/* Flare style. */
58 	float		dist;			/* Distance to flare. */
59 	image_t        *flare;			/* Flare image. */
60 	vec3_t		color;			/* Flare color. */
61 	vec3_t		vec;			/* Vector distance to flare. */
62 	vec3_t		point;			/* For flare coordinates. */
63 
64 	/* Check for flare style override. */
65 	if (gl_flare_force_style->value > 0 &&
66 	    gl_flare_force_style->value <= FLARE_STYLES)
67 		style = gl_flare_force_style->value;
68 	else
69 		style = light->style;
70 
71 	/* Check if style is valid. */
72 	if (style > 0 && style <= FLARE_STYLES)
73 		Com_sprintf(pathname, sizeof(pathname),
74 		    "gfx/flare%d.png", style);
75 	else
76 		ri.Sys_Error(ERR_DROP,
77 		    "R_RenderFlare: invalid flare style: %d", style);
78 
79 	flare = GL_FindImage(pathname, it_sprite);
80 
81 	if (flare == NULL)
82 		flare = r_notexture;
83 
84 	/* Check for flare size override. */
85 	if (gl_flare_force_size->value != 0)
86 		size = gl_flare_force_size->value;
87 	else
88 		size = light->size * gl_flare_scale->value;
89 
90 	/* Adjust flare intensity. */
91 	VectorScale(light->color, gl_flare_intensity->value, color);
92 
93 	/* Calculate size based on distance. */
94 	VectorSubtract(light->origin, r_origin, vec);
95 	dist = VectorLength(vec) * (size * 0.01);
96 
97 	/* Limit flare size. */
98 	if (gl_flare_maxdist->value != 0)
99 		if (dist > gl_flare_maxdist->value)
100 			dist = gl_flare_maxdist->value;
101 
102 	qglDisable(GL_DEPTH_TEST);
103 	qglEnable(GL_TEXTURE_2D);
104 	qglColor4f(color[0] / 2, color[1] / 2, color[2] / 2, 1);
105 	GL_Bind(flare->texnum);
106 
107 	GL_TexEnv(GL_MODULATE);
108 
109 	qglBegin(GL_QUADS);
110 
111 #if 0
112 	/* Shorter, but expensive (needs more calculations). */
113 	for (i = 0; i < 2; i++)
114 		for (i ? (j = 0) : (j = 1);
115 		    i ? (j < 2) : (j >= 0);
116 		    i ? (j++) : (j--)) {
117 			qglTexCoord2f(i, j);
118 			VectorMA(light->origin, i ? (1 + dist) : (-1 - dist),
119 			    vup, point);
120 			VectorMA(point, j ? (1 + dist) : (-1 - dist),
121 			    vright, point);
122 			qglVertex3fv(point);
123 		}
124 #endif
125 
126 	qglTexCoord2f(0, 1);
127 	VectorMA(light->origin, -1-dist, vup, point);
128 	VectorMA(point, 1+dist, vright, point);
129 	qglVertex3fv(point);
130 
131 	qglTexCoord2f(0, 0);
132 	VectorMA(light->origin, -1-dist, vup, point);
133 	VectorMA(point, -1-dist, vright, point);
134 	qglVertex3fv (point);
135 
136 	qglTexCoord2f(1, 0);
137 	VectorMA(light->origin, 1+dist, vup, point);
138 	VectorMA(point, -1-dist, vright, point);
139 	qglVertex3fv(point);
140 
141 	qglTexCoord2f(1, 1);
142 	VectorMA(light->origin, 1+dist, vup, point);
143 	VectorMA(point, 1+dist, vright, point);
144 	qglVertex3fv(point);
145 
146 	qglEnd();
147 
148 	GL_TexEnv(GL_REPLACE);
149 	qglEnable(GL_DEPTH_TEST);
150 	qglDisable(GL_TEXTURE_2D);
151 	qglColor3f(0, 0, 0);
152 }
153 
154 void
GL_AddFlareSurface(msurface_t * surf)155 GL_AddFlareSurface(msurface_t * surf)
156 {
157 	int		intens;	/* Light intensity. */
158 	flare_t        *light;	/* New flare. */
159 	vec3_t		origin;	/* Center of surface. */
160 	vec3_t		color;	/* Flare color. */
161 	vec3_t		normal;	/* Normal vector. */
162 
163 	/* Check for free flares. */
164 	if (r_numflares >= MAX_FLARES)
165 		return;
166 
167 	/* Initialization. */
168 	VectorClear(origin);
169 	VectorSet(color, 1.0, 1.0, 1.0);
170 
171 	intens = surf->texinfo->value;
172 
173 	/* Skip very small or null lights. */
174 	if (intens <= 1000) {
175 		ri.Con_Printf(PRINT_DEVELOPER,
176 		    "Skipped flare surface with intensity of %d.\n", intens);
177 		return;
178 	}
179 
180 	/* Create new flare. */
181 	light = Hunk_Alloc(sizeof(flare_t));
182 	r_flares[r_numflares++] = light;
183 
184 	VectorCopy(surf->center, origin);
185 
186 #if 0
187 	/* Calculate color average of light surface texture. */
188 	GL_Bind(surf->texinfo->image->texnum);
189 	width = surf->texinfo->image->upload_width;
190 	height = surf->texinfo->image->upload_height;
191 
192 	buffer = malloc(width * height * 3);
193 	qglGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
194 	VectorClear(rgbSum);
195 
196 	for (i = 0, p = buffer; i < width * height; i++, p += 3)
197 		rgbSum[i % 3] += (float)p[i % 3] * (1.0 / 255);
198 
199 	free(buffer);
200 
201 	VectorScale(rgbSum, 1.0 / (width*height), color);
202 	VectorCopy(color, light->color);
203 #else
204 	if (surf->wallLight != NULL)
205 		VectorCopy(surf->wallLight->color, light->color);
206 	else
207 		VectorSet(light->color, 1.0, 1.0, 1.0);
208 #endif
209 
210 	/* Move flare 2 units far from the surface. */
211 	if (surf->flags & SURF_PLANEBACK)
212 		VectorNegate(surf->plane->normal, normal);
213 	else
214 		VectorCopy(surf->plane->normal, normal);
215 
216 	VectorMA(origin, 2, normal, origin);
217 	VectorCopy(origin, light->origin);
218 
219 	light->style = r_numflares % FLARE_STYLES + 1;	/* Pseudo-random. */
220 	light->size = intens / 1000;
221 
222 	ri.Con_Printf(PRINT_DEVELOPER, "Added flare on light surface %d: "
223 	    "size = %d, style = %d, red = %f, green = %f, blue = %f,"
224 	    "x = %f, y = %f, z = %f.\n", r_numflares, light->size,
225 	    light->style, light->color[0], light->color[1], light->color[2],
226 	    light->origin[0], light->origin[1], light->origin[2]);
227 }
228