1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20// r_light.c 21 22#include "quakedef.h" 23#include "r_local.h" 24 25int r_dlightframecount; 26 27 28/* 29================== 30R_AnimateLight 31================== 32*/ 33void R_AnimateLight (void) 34{ 35 int i,j,k; 36 37// 38// light animations 39// 'm' is normal light, 'a' is no light, 'z' is double bright 40 i = (int)(cl.time*10); 41 for (j=0 ; j<MAX_LIGHTSTYLES ; j++) 42 { 43 if (!cl_lightstyle[j].length) 44 { 45 d_lightstylevalue[j] = 256; 46 continue; 47 } 48 k = i % cl_lightstyle[j].length; 49 k = cl_lightstyle[j].map[k] - 'a'; 50 k = k*22; 51 d_lightstylevalue[j] = k; 52 } 53} 54 55 56/* 57============================================================================= 58 59DYNAMIC LIGHTS 60 61============================================================================= 62*/ 63 64/* 65============= 66R_MarkLights 67============= 68*/ 69void R_MarkLights (dlight_t *light, int bit, mnode_t *node) 70{ 71 mplane_t *splitplane; 72 float dist; 73 msurface_t *surf; 74 int i; 75 76 if (node->contents < 0) 77 return; 78 79 splitplane = node->plane; 80 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; 81 82 if (dist > light->radius) 83 { 84 R_MarkLights (light, bit, node->children[0]); 85 return; 86 } 87 if (dist < -light->radius) 88 { 89 R_MarkLights (light, bit, node->children[1]); 90 return; 91 } 92 93// mark the polygons 94 surf = cl.worldmodel->surfaces + node->firstsurface; 95 for (i=0 ; i<node->numsurfaces ; i++, surf++) 96 { 97 if (surf->dlightframe != r_dlightframecount) 98 { 99 surf->dlightbits = 0; 100 surf->dlightframe = r_dlightframecount; 101 } 102 surf->dlightbits |= bit; 103 } 104 105 R_MarkLights (light, bit, node->children[0]); 106 R_MarkLights (light, bit, node->children[1]); 107} 108 109 110/* 111============= 112R_PushDlights 113============= 114*/ 115void R_PushDlights (void) 116{ 117 int i; 118 dlight_t *l; 119 120 r_dlightframecount = r_framecount + 1; // because the count hasn't 121 // advanced yet for this frame 122 l = cl_dlights; 123 124 for (i=0 ; i<MAX_DLIGHTS ; i++, l++) 125 { 126 if (l->die < cl.time || !l->radius) 127 continue; 128 R_MarkLights ( l, 1<<i, cl.worldmodel->nodes ); 129 } 130} 131 132 133/* 134============================================================================= 135 136LIGHT SAMPLING 137 138============================================================================= 139*/ 140 141int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) 142{ 143 int r; 144 float front, back, frac; 145 int side; 146 mplane_t *plane; 147 vec3_t mid; 148 msurface_t *surf; 149 int s, t, ds, dt; 150 int i; 151 mtexinfo_t *tex; 152 byte *lightmap; 153 unsigned scale; 154 int maps; 155 156 if (node->contents < 0) 157 return -1; // didn't hit anything 158 159// calculate mid point 160 161// FIXME: optimize for axial 162 plane = node->plane; 163 front = DotProduct (start, plane->normal) - plane->dist; 164 back = DotProduct (end, plane->normal) - plane->dist; 165 side = front < 0; 166 167 if ( (back < 0) == side) 168 return RecursiveLightPoint (node->children[side], start, end); 169 170 frac = front / (front-back); 171 mid[0] = start[0] + (end[0] - start[0])*frac; 172 mid[1] = start[1] + (end[1] - start[1])*frac; 173 mid[2] = start[2] + (end[2] - start[2])*frac; 174 175// go down front side 176 r = RecursiveLightPoint (node->children[side], start, mid); 177 if (r >= 0) 178 return r; // hit something 179 180 if ( (back < 0) == side ) 181 return -1; // didn't hit anuthing 182 183// check for impact on this node 184 185 surf = cl.worldmodel->surfaces + node->firstsurface; 186 for (i=0 ; i<node->numsurfaces ; i++, surf++) 187 { 188 if (surf->flags & SURF_DRAWTILED) 189 continue; // no lightmaps 190 191 tex = surf->texinfo; 192 193 s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; 194 t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; 195 196 if (s < surf->texturemins[0] || 197 t < surf->texturemins[1]) 198 continue; 199 200 ds = s - surf->texturemins[0]; 201 dt = t - surf->texturemins[1]; 202 203 if ( ds > surf->extents[0] || dt > surf->extents[1] ) 204 continue; 205 206 if (!surf->samples) 207 return 0; 208 209 ds >>= 4; 210 dt >>= 4; 211 212 lightmap = surf->samples; 213 r = 0; 214 if (lightmap) 215 { 216 217 lightmap += dt * ((surf->extents[0]>>4)+1) + ds; 218 219 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 220 maps++) 221 { 222 scale = d_lightstylevalue[surf->styles[maps]]; 223 r += *lightmap * scale; 224 lightmap += ((surf->extents[0]>>4)+1) * 225 ((surf->extents[1]>>4)+1); 226 } 227 228 r >>= 8; 229 } 230 231 return r; 232 } 233 234// go down back side 235 return RecursiveLightPoint (node->children[!side], mid, end); 236} 237 238int R_LightPoint (vec3_t p) 239{ 240 vec3_t end; 241 int r; 242 243 if (!cl.worldmodel->lightdata) 244 return 255; 245 246 end[0] = p[0]; 247 end[1] = p[1]; 248 end[2] = p[2] - 2048; 249 250 r = RecursiveLightPoint (cl.worldmodel->nodes, p, end); 251 252 if (r == -1) 253 r = 0; 254 255 if (r < r_refdef.ambientlight) 256 r = r_refdef.ambientlight; 257 258 return r; 259} 260 261