1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright 2006 - 2008 G Jackson, Jaakko Ker�nen
8 * Copyright 2009 - Andrey Budko
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 * 02111-1307, USA.
24 *
25 * DESCRIPTION: Shadow rendering
26 * Based on Risen3D implementation which is based on Doomsday v1.7.8.
27 *---------------------------------------------------------------------
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "gl_opengl.h"
35 #include "gl_intern.h"
36 #include "doomstat.h"
37 #include "p_maputl.h"
38 #include "w_wad.h"
39 #include "r_bsp.h"
40 #include "r_sky.h"
41 #include "lprintf.h"
42
43 int gl_shadows_maxdist;
44 int gl_shadows_factor;
45
46 simple_shadow_params_t simple_shadows =
47 {
48 0, 0,
49 -1, 0, 0,
50 80, 1000, 0.5f, 0.0044f
51 };
52
53 //===========================================================================
54 // GL_PrepareLightTexture
55 // The dynamic light map is a 64x64 grayscale 8-bit image.
56 //===========================================================================
gld_InitShadows(void)57 void gld_InitShadows(void)
58 {
59 int lump;
60
61 simple_shadows.loaded = false;
62
63 simple_shadows.tex_id = -1;
64 simple_shadows.width = 0;
65 simple_shadows.height = 0;
66
67 simple_shadows.max_radius = 80;
68 simple_shadows.max_dist = gl_shadows_maxdist;
69 simple_shadows.factor = (float)gl_shadows_factor / 256.0f;
70 simple_shadows.bias = 0.0044f;
71
72 lump = (W_CheckNumForName)("GLSHADOW", ns_prboom);
73 if (lump != -1)
74 {
75 SDL_PixelFormat fmt;
76 SDL_Surface *surf = NULL;
77 SDL_Surface *surf_raw;
78 surf_raw = SDL_LoadBMP_RW(SDL_RWFromConstMem(W_CacheLumpNum(lump), W_LumpLength(lump)), 1);
79 W_UnlockLumpNum(lump);
80
81 fmt = *surf_raw->format;
82 fmt.BitsPerPixel = 24;
83 fmt.BytesPerPixel = 3;
84
85 surf = SDL_ConvertSurface(surf_raw, &fmt, surf_raw->flags);
86 SDL_FreeSurface(surf_raw);
87 if (surf)
88 {
89 glGenTextures(1, &simple_shadows.tex_id);
90 glBindTexture(GL_TEXTURE_2D, simple_shadows.tex_id);
91
92 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, surf->w, surf->h, 0, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels);
93
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
96 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
98 if (gl_ext_texture_filter_anisotropic)
99 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (GLfloat)(1<<gl_texture_filter_anisotropic));
100
101 simple_shadows.loaded = true;
102 simple_shadows.width = surf->w;
103 simple_shadows.height = surf->h;
104
105 SDL_FreeSurface(surf);
106 }
107 }
108
109 if (simple_shadows.enable && !simple_shadows.loaded)
110 {
111 lprintf(LO_INFO, "gld_InitShadows: failed to initialise shadow texture");
112 }
113 }
114
gld_DrawShadow(GLShadow * shadow)115 static void gld_DrawShadow(GLShadow *shadow)
116 {
117 glColor3f(shadow->light, shadow->light, shadow->light);
118
119 glBegin(GL_TRIANGLE_FAN);
120
121 glTexCoord2f(1.0f, 0.0f);
122 glVertex3f(shadow->x + shadow->radius, shadow->z, shadow->y - shadow->radius);
123 glTexCoord2f(0.0f, 0.0f);
124 glVertex3f(shadow->x - shadow->radius, shadow->z, shadow->y - shadow->radius);
125 glTexCoord2f(0.0f, 1.0f);
126 glVertex3f(shadow->x - shadow->radius, shadow->z, shadow->y + shadow->radius);
127 glTexCoord2f(1.0f, 1.0f);
128 glVertex3f(shadow->x + shadow->radius, shadow->z, shadow->y + shadow->radius);
129
130 glEnd();
131 }
132
133 //===========================================================================
134 // Rend_ProcessThingShadow
135 // Modified for z-smoothing - R3D
136 //===========================================================================
gld_ProcessThingShadow(mobj_t * mo)137 void gld_ProcessThingShadow(mobj_t *mo)
138 {
139 int dist;
140 float height, moh, halfmoh;
141 sector_t *sec = mo->subsector->sector;
142 int radius, z;
143 GLShadow shadow;
144
145 if (!simple_shadows.enable || !simple_shadows.loaded)
146 return;
147
148 // Should this mobj have a shadow?
149 if (mo->flags & (MF_SHADOW|MF_NOBLOCKMAP|MF_NOSECTOR))
150 return;
151
152 if (mo->frame & FF_FULLBRIGHT)
153 return;
154
155 // Don't render mobj shadows on sky floors.
156 if (mo->subsector->sector->floorpic == skyflatnum)
157 return;
158
159 if (sectorloops[sec->iSectorID].loopcount <= 0)
160 return;
161
162 // Is this too far?
163 dist = P_AproxDistance((mo->x >> 16) - (viewx >> 16), (mo->y >> 16) - (viewy >> 16));
164 if (dist > simple_shadows.max_dist)
165 return;
166
167 // Check the height.
168 if (sec->heightsec != -1)
169 z = sectors[sec->heightsec].floorheight;
170 else
171 z = sec->floorheight;
172
173 // below visible floor
174 if (mo->z < z)
175 return;
176
177 height = (mo->z - z) / (float)FRACUNIT;
178 moh = mo->height / (float)FRACUNIT;
179 if(!moh)
180 moh = 1;
181
182 // Too high above floor.
183 if(height > moh)
184 return;
185
186 // Calculate the strength of the shadow.
187
188 shadow.light = simple_shadows.factor * sec->lightlevel / 255.0f;
189
190 halfmoh = moh * 0.5f;
191 if(height > halfmoh)
192 shadow.light *= 1 - (height - halfmoh) / (moh - halfmoh);
193
194 // Can't be seen.
195 if(shadow.light <= 0)
196 return;
197
198 if(shadow.light > 1)
199 shadow.light = 1;
200
201 // Calculate the radius of the shadow.
202 radius = mo->info->radius >> 16;
203 if (radius > mo->patch_width >> 1)
204 radius = mo->patch_width >> 1;
205 if(radius > simple_shadows.max_radius)
206 radius = simple_shadows.max_radius;
207 if(!radius)
208 return;
209
210 shadow.radius = radius / MAP_COEFF;
211 shadow.x = -mo->x / MAP_SCALE;
212 shadow.y = mo->y / MAP_SCALE;
213 shadow.z = mo->subsector->sector->floorheight / MAP_SCALE + 0.2f / MAP_COEFF;
214
215 gld_AddDrawItem(GLDIT_SHADOW, &shadow);
216 }
217
218 //===========================================================================
219 // Rend_RenderShadows
220 //===========================================================================
gld_RenderShadows(void)221 void gld_RenderShadows(void)
222 {
223 int i;
224
225 if (!simple_shadows.enable || !simple_shadows.loaded || players[displayplayer].fixedcolormap)
226 return;
227
228 if (gld_drawinfo.num_items[GLDIT_SHADOW] <= 0)
229 return;
230
231 if (!gl_ztrick)
232 {
233 glDepthRange(simple_shadows.bias, 1);
234 }
235
236 gl_EnableFog(false);
237
238 glDepthMask(GL_FALSE);
239 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
240
241 // Apply a modelview shift.
242 glMatrixMode(GL_MODELVIEW);
243 glPushMatrix();
244
245 // Scale towards the viewpoint to avoid Z-fighting.
246 glTranslatef(xCamera, zCamera, yCamera);
247 glScalef(0.99f, 0.99f, 0.99f);
248 glTranslatef(-xCamera, -zCamera, -yCamera);
249
250 glBindTexture(GL_TEXTURE_2D, simple_shadows.tex_id);
251 gld_ResetLastTexture();
252
253 for (i = gld_drawinfo.num_items[GLDIT_SHADOW] - 1; i >= 0; i--)
254 {
255 gld_DrawShadow(gld_drawinfo.items[GLDIT_SHADOW][i].item.shadow);
256 }
257
258 if (!gl_ztrick)
259 {
260 glDepthRange(0, 1);
261 }
262
263 glPopMatrix();
264 glDepthMask(GL_TRUE);
265 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
266 }
267