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