1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or 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 16 along with this program; if not, write to the Free Software 17 Foundation, 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 25 int r_dlightframecount; 26 27 28 /* 29 ================== 30 R_AnimateLight 31 ================== 32 */ 33 void 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 59 DYNAMIC LIGHTS 60 61 ============================================================================= 62 */ 63 64 /* 65 ============= 66 R_MarkLights 67 ============= 68 */ 69 void 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 ============= 112 R_PushDlights 113 ============= 114 */ 115 void 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 136 LIGHT SAMPLING 137 138 ============================================================================= 139 */ 140 141 int 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 238 int 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