r_light.c (8912B)
1 /* 2 Copyright (C) 1997-2001 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 "r_local.h" 23 24 int r_dlightframecount; 25 26 27 /* 28 ============================================================================= 29 30 DYNAMIC LIGHTS 31 32 ============================================================================= 33 */ 34 35 /* 36 ============= 37 R_MarkLights 38 ============= 39 */ 40 void R_MarkLights (dlight_t *light, int bit, mnode_t *node) 41 { 42 mplane_t *splitplane; 43 float dist; 44 msurface_t *surf; 45 int i; 46 47 if (node->contents != -1) 48 return; 49 50 splitplane = node->plane; 51 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; 52 53 //===== 54 //PGM 55 i=light->intensity; 56 if(i<0) 57 i=-i; 58 //PGM 59 //===== 60 61 if (dist > i) // PGM (dist > light->intensity) 62 { 63 R_MarkLights (light, bit, node->children[0]); 64 return; 65 } 66 if (dist < -i) // PGM (dist < -light->intensity) 67 { 68 R_MarkLights (light, bit, node->children[1]); 69 return; 70 } 71 72 // mark the polygons 73 surf = r_worldmodel->surfaces + node->firstsurface; 74 for (i=0 ; i<node->numsurfaces ; i++, surf++) 75 { 76 if (surf->dlightframe != r_dlightframecount) 77 { 78 surf->dlightbits = 0; 79 surf->dlightframe = r_dlightframecount; 80 } 81 surf->dlightbits |= bit; 82 } 83 84 R_MarkLights (light, bit, node->children[0]); 85 R_MarkLights (light, bit, node->children[1]); 86 } 87 88 89 /* 90 ============= 91 R_PushDlights 92 ============= 93 */ 94 void R_PushDlights (model_t *model) 95 { 96 int i; 97 dlight_t *l; 98 99 r_dlightframecount = r_framecount; 100 for (i=0, l = r_newrefdef.dlights ; i<r_newrefdef.num_dlights ; i++, l++) 101 { 102 R_MarkLights ( l, 1<<i, 103 model->nodes + model->firstnode); 104 } 105 } 106 107 108 /* 109 ============================================================================= 110 111 LIGHT SAMPLING 112 113 ============================================================================= 114 */ 115 116 vec3_t pointcolor; 117 mplane_t *lightplane; // used as shadow plane 118 vec3_t lightspot; 119 120 int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) 121 { 122 float front, back, frac; 123 int side; 124 mplane_t *plane; 125 vec3_t mid; 126 msurface_t *surf; 127 int s, t, ds, dt; 128 int i; 129 mtexinfo_t *tex; 130 byte *lightmap; 131 float *scales; 132 int maps; 133 float samp; 134 int r; 135 136 if (node->contents != -1) 137 return -1; // didn't hit anything 138 139 // calculate mid point 140 141 // FIXME: optimize for axial 142 plane = node->plane; 143 front = DotProduct (start, plane->normal) - plane->dist; 144 back = DotProduct (end, plane->normal) - plane->dist; 145 side = front < 0; 146 147 if ( (back < 0) == side) 148 return RecursiveLightPoint (node->children[side], start, end); 149 150 frac = front / (front-back); 151 mid[0] = start[0] + (end[0] - start[0])*frac; 152 mid[1] = start[1] + (end[1] - start[1])*frac; 153 mid[2] = start[2] + (end[2] - start[2])*frac; 154 if (plane->type < 3) // axial planes 155 mid[plane->type] = plane->dist; 156 157 // go down front side 158 r = RecursiveLightPoint (node->children[side], start, mid); 159 if (r >= 0) 160 return r; // hit something 161 162 if ( (back < 0) == side ) 163 return -1; // didn't hit anuthing 164 165 // check for impact on this node 166 VectorCopy (mid, lightspot); 167 lightplane = plane; 168 169 surf = r_worldmodel->surfaces + node->firstsurface; 170 for (i=0 ; i<node->numsurfaces ; i++, surf++) 171 { 172 if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 173 continue; // no lightmaps 174 175 tex = surf->texinfo; 176 177 s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; 178 t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3]; 179 if (s < surf->texturemins[0] || 180 t < surf->texturemins[1]) 181 continue; 182 183 ds = s - surf->texturemins[0]; 184 dt = t - surf->texturemins[1]; 185 186 if ( ds > surf->extents[0] || dt > surf->extents[1] ) 187 continue; 188 189 if (!surf->samples) 190 return 0; 191 192 ds >>= 4; 193 dt >>= 4; 194 195 lightmap = surf->samples; 196 VectorCopy (vec3_origin, pointcolor); 197 if (lightmap) 198 { 199 lightmap += dt * ((surf->extents[0]>>4)+1) + ds; 200 201 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 202 maps++) 203 { 204 samp = *lightmap * /* 0.5 * */ (1.0/255); // adjust for gl scale 205 scales = r_newrefdef.lightstyles[surf->styles[maps]].rgb; 206 VectorMA (pointcolor, samp, scales, pointcolor); 207 lightmap += ((surf->extents[0]>>4)+1) * 208 ((surf->extents[1]>>4)+1); 209 } 210 } 211 212 return 1; 213 } 214 215 // go down back side 216 return RecursiveLightPoint (node->children[!side], mid, end); 217 } 218 219 /* 220 =============== 221 R_LightPoint 222 =============== 223 */ 224 void R_LightPoint (vec3_t p, vec3_t color) 225 { 226 vec3_t end; 227 float r; 228 int lnum; 229 dlight_t *dl; 230 float light; 231 vec3_t dist; 232 float add; 233 234 if (!r_worldmodel->lightdata) 235 { 236 color[0] = color[1] = color[2] = 1.0; 237 return; 238 } 239 240 end[0] = p[0]; 241 end[1] = p[1]; 242 end[2] = p[2] - 2048; 243 244 r = RecursiveLightPoint (r_worldmodel->nodes, p, end); 245 246 if (r == -1) 247 { 248 VectorCopy (vec3_origin, color); 249 } 250 else 251 { 252 VectorCopy (pointcolor, color); 253 } 254 255 // 256 // add dynamic lights 257 // 258 light = 0; 259 for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++) 260 { 261 dl = &r_newrefdef.dlights[lnum]; 262 VectorSubtract (currententity->origin, 263 dl->origin, 264 dist); 265 add = dl->intensity - VectorLength(dist); 266 add *= (1.0/256); 267 if (add > 0) 268 { 269 VectorMA (color, add, dl->color, color); 270 } 271 } 272 } 273 274 //=================================================================== 275 276 277 unsigned blocklights[1024]; // allow some very large lightmaps 278 279 /* 280 =============== 281 R_AddDynamicLights 282 =============== 283 */ 284 void R_AddDynamicLights (void) 285 { 286 msurface_t *surf; 287 int lnum; 288 int sd, td; 289 float dist, rad, minlight; 290 vec3_t impact, local; 291 int s, t; 292 int i; 293 int smax, tmax; 294 mtexinfo_t *tex; 295 dlight_t *dl; 296 int negativeLight; //PGM 297 298 surf = r_drawsurf.surf; 299 smax = (surf->extents[0]>>4)+1; 300 tmax = (surf->extents[1]>>4)+1; 301 tex = surf->texinfo; 302 303 for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++) 304 { 305 if ( !(surf->dlightbits & (1<<lnum) ) ) 306 continue; // not lit by this light 307 308 dl = &r_newrefdef.dlights[lnum]; 309 rad = dl->intensity; 310 311 //===== 312 //PGM 313 negativeLight = 0; 314 if(rad < 0) 315 { 316 negativeLight = 1; 317 rad = -rad; 318 } 319 //PGM 320 //===== 321 322 dist = DotProduct (dl->origin, surf->plane->normal) - 323 surf->plane->dist; 324 rad -= fabs(dist); 325 minlight = 32; // dl->minlight; 326 if (rad < minlight) 327 continue; 328 minlight = rad - minlight; 329 330 for (i=0 ; i<3 ; i++) 331 { 332 impact[i] = dl->origin[i] - 333 surf->plane->normal[i]*dist; 334 } 335 336 local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; 337 local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; 338 339 local[0] -= surf->texturemins[0]; 340 local[1] -= surf->texturemins[1]; 341 342 for (t = 0 ; t<tmax ; t++) 343 { 344 td = local[1] - t*16; 345 if (td < 0) 346 td = -td; 347 for (s=0 ; s<smax ; s++) 348 { 349 sd = local[0] - s*16; 350 if (sd < 0) 351 sd = -sd; 352 if (sd > td) 353 dist = sd + (td>>1); 354 else 355 dist = td + (sd>>1); 356 //==== 357 //PGM 358 if(!negativeLight) 359 { 360 if (dist < minlight) 361 blocklights[t*smax + s] += (rad - dist)*256; 362 } 363 else 364 { 365 if (dist < minlight) 366 blocklights[t*smax + s] -= (rad - dist)*256; 367 if(blocklights[t*smax + s] < minlight) 368 blocklights[t*smax + s] = minlight; 369 } 370 //PGM 371 //==== 372 } 373 } 374 } 375 } 376 377 /* 378 =============== 379 R_BuildLightMap 380 381 Combine and scale multiple lightmaps into the 8.8 format in blocklights 382 =============== 383 */ 384 void R_BuildLightMap (void) 385 { 386 int smax, tmax; 387 int t; 388 int i, size; 389 byte *lightmap; 390 unsigned scale; 391 int maps; 392 msurface_t *surf; 393 394 surf = r_drawsurf.surf; 395 396 smax = (surf->extents[0]>>4)+1; 397 tmax = (surf->extents[1]>>4)+1; 398 size = smax*tmax; 399 400 if (r_fullbright->value || !r_worldmodel->lightdata) 401 { 402 for (i=0 ; i<size ; i++) 403 blocklights[i] = 0; 404 return; 405 } 406 407 // clear to no light 408 for (i=0 ; i<size ; i++) 409 blocklights[i] = 0; 410 411 412 // add all the lightmaps 413 lightmap = surf->samples; 414 if (lightmap) 415 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 416 maps++) 417 { 418 scale = r_drawsurf.lightadj[maps]; // 8.8 fraction 419 for (i=0 ; i<size ; i++) 420 blocklights[i] += lightmap[i] * scale; 421 lightmap += size; // skip to next lightmap 422 } 423 424 // add all the dynamic lights 425 if (surf->dlightframe == r_framecount) 426 R_AddDynamicLights (); 427 428 // bound, invert, and shift 429 for (i=0 ; i<size ; i++) 430 { 431 t = (int)blocklights[i]; 432 if (t < 0) 433 t = 0; 434 t = (255*256 - t) >> (8 - VID_CBITS); 435 436 if (t < (1 << 6)) 437 t = (1 << 6); 438 439 blocklights[i] = t; 440 } 441 } 442