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_surf.c: surface-related refresh code 21 22#include "quakedef.h" 23#include "r_local.h" 24 25drawsurf_t r_drawsurf; 26 27int lightleft, sourcesstep, blocksize, sourcetstep; 28int lightdelta, lightdeltastep; 29int lightright, lightleftstep, lightrightstep, blockdivshift; 30unsigned blockdivmask; 31void *prowdestbase; 32unsigned char *pbasesource; 33int surfrowbytes; // used by ASM files 34unsigned *r_lightptr; 35int r_stepback; 36int r_lightwidth; 37int r_numhblocks, r_numvblocks; 38unsigned char *r_source, *r_sourcemax; 39 40void R_DrawSurfaceBlock8_mip0 (void); 41void R_DrawSurfaceBlock8_mip1 (void); 42void R_DrawSurfaceBlock8_mip2 (void); 43void R_DrawSurfaceBlock8_mip3 (void); 44 45static void (*surfmiptable[4])(void) = { 46 R_DrawSurfaceBlock8_mip0, 47 R_DrawSurfaceBlock8_mip1, 48 R_DrawSurfaceBlock8_mip2, 49 R_DrawSurfaceBlock8_mip3 50}; 51 52 53 54unsigned blocklights[18*18]; 55 56/* 57=============== 58R_AddDynamicLights 59=============== 60*/ 61void R_AddDynamicLights (void) 62{ 63 msurface_t *surf; 64 int lnum; 65 int sd, td; 66 float dist, rad, minlight; 67 vec3_t impact, local; 68 int s, t; 69 int i; 70 int smax, tmax; 71 mtexinfo_t *tex; 72 73 surf = r_drawsurf.surf; 74 smax = (surf->extents[0]>>4)+1; 75 tmax = (surf->extents[1]>>4)+1; 76 tex = surf->texinfo; 77 78 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) 79 { 80 if ( !(surf->dlightbits & (1<<lnum) ) ) 81 continue; // not lit by this light 82 83 rad = cl_dlights[lnum].radius; 84 dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) - 85 surf->plane->dist; 86 rad -= fabs(dist); 87 minlight = cl_dlights[lnum].minlight; 88 if (rad < minlight) 89 continue; 90 minlight = rad - minlight; 91 92 for (i=0 ; i<3 ; i++) 93 { 94 impact[i] = cl_dlights[lnum].origin[i] - 95 surf->plane->normal[i]*dist; 96 } 97 98 local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; 99 local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; 100 101 local[0] -= surf->texturemins[0]; 102 local[1] -= surf->texturemins[1]; 103 104 for (t = 0 ; t<tmax ; t++) 105 { 106 td = local[1] - t*16; 107 if (td < 0) 108 td = -td; 109 for (s=0 ; s<smax ; s++) 110 { 111 sd = local[0] - s*16; 112 if (sd < 0) 113 sd = -sd; 114 if (sd > td) 115 dist = sd + (td>>1); 116 else 117 dist = td + (sd>>1); 118 if (dist < minlight) 119#ifdef QUAKE2 120 { 121 unsigned temp; 122 temp = (rad - dist)*256; 123 i = t*smax + s; 124 if (!cl_dlights[lnum].dark) 125 blocklights[i] += temp; 126 else 127 { 128 if (blocklights[i] > temp) 129 blocklights[i] -= temp; 130 else 131 blocklights[i] = 0; 132 } 133 } 134#else 135 blocklights[t*smax + s] += (rad - dist)*256; 136#endif 137 } 138 } 139 } 140} 141 142/* 143=============== 144R_BuildLightMap 145 146Combine and scale multiple lightmaps into the 8.8 format in blocklights 147=============== 148*/ 149void R_BuildLightMap (void) 150{ 151 int smax, tmax; 152 int t; 153 int i, size; 154 byte *lightmap; 155 unsigned scale; 156 int maps; 157 msurface_t *surf; 158 159 surf = r_drawsurf.surf; 160 161 smax = (surf->extents[0]>>4)+1; 162 tmax = (surf->extents[1]>>4)+1; 163 size = smax*tmax; 164 lightmap = surf->samples; 165 166 if (r_fullbright.value || !cl.worldmodel->lightdata) 167 { 168 for (i=0 ; i<size ; i++) 169 blocklights[i] = 0; 170 return; 171 } 172 173// clear to ambient 174 for (i=0 ; i<size ; i++) 175 blocklights[i] = r_refdef.ambientlight<<8; 176 177 178// add all the lightmaps 179 if (lightmap) 180 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 181 maps++) 182 { 183 scale = r_drawsurf.lightadj[maps]; // 8.8 fraction 184 for (i=0 ; i<size ; i++) 185 blocklights[i] += lightmap[i] * scale; 186 lightmap += size; // skip to next lightmap 187 } 188 189// add all the dynamic lights 190 if (surf->dlightframe == r_framecount) 191 R_AddDynamicLights (); 192 193// bound, invert, and shift 194 for (i=0 ; i<size ; i++) 195 { 196 t = (255*256 - (int)blocklights[i]) >> (8 - VID_CBITS); 197 198 if (t < (1 << 6)) 199 t = (1 << 6); 200 201 blocklights[i] = t; 202 } 203} 204 205 206/* 207=============== 208R_TextureAnimation 209 210Returns the proper texture for a given time and base texture 211=============== 212*/ 213texture_t *R_TextureAnimation (texture_t *base) 214{ 215 int reletive; 216 int count; 217 218 if (currententity->frame) 219 { 220 if (base->alternate_anims) 221 base = base->alternate_anims; 222 } 223 224 if (!base->anim_total) 225 return base; 226 227 reletive = (int)(cl.time*10) % base->anim_total; 228 229 count = 0; 230 while (base->anim_min > reletive || base->anim_max <= reletive) 231 { 232 base = base->anim_next; 233 if (!base) 234 Sys_Error ("R_TextureAnimation: broken cycle"); 235 if (++count > 100) 236 Sys_Error ("R_TextureAnimation: infinite cycle"); 237 } 238 239 return base; 240} 241 242 243/* 244=============== 245R_DrawSurface 246=============== 247*/ 248void R_DrawSurface (void) 249{ 250 unsigned char *basetptr; 251 int smax, tmax, twidth; 252 int u; 253 int soffset, basetoffset, texwidth; 254 int horzblockstep; 255 unsigned char *pcolumndest; 256 void (*pblockdrawer)(void); 257 texture_t *mt; 258 259// calculate the lightings 260 R_BuildLightMap (); 261 262 surfrowbytes = r_drawsurf.rowbytes; 263 264 mt = r_drawsurf.texture; 265 266 r_source = (byte *)mt + mt->offsets[r_drawsurf.surfmip]; 267 268// the fractional light values should range from 0 to (VID_GRADES - 1) << 16 269// from a source range of 0 - 255 270 271 texwidth = mt->width >> r_drawsurf.surfmip; 272 273 blocksize = 16 >> r_drawsurf.surfmip; 274 blockdivshift = 4 - r_drawsurf.surfmip; 275 blockdivmask = (1 << blockdivshift) - 1; 276 277 r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1; 278 279 r_numhblocks = r_drawsurf.surfwidth >> blockdivshift; 280 r_numvblocks = r_drawsurf.surfheight >> blockdivshift; 281 282//============================== 283 284 if (r_pixbytes == 1) 285 { 286 pblockdrawer = surfmiptable[r_drawsurf.surfmip]; 287 // TODO: only needs to be set when there is a display settings change 288 horzblockstep = blocksize; 289 } 290 else 291 { 292 pblockdrawer = R_DrawSurfaceBlock16; 293 // TODO: only needs to be set when there is a display settings change 294 horzblockstep = blocksize << 1; 295 } 296 297 smax = mt->width >> r_drawsurf.surfmip; 298 twidth = texwidth; 299 tmax = mt->height >> r_drawsurf.surfmip; 300 sourcetstep = texwidth; 301 r_stepback = tmax * twidth; 302 303 r_sourcemax = r_source + (tmax * smax); 304 305 soffset = r_drawsurf.surf->texturemins[0]; 306 basetoffset = r_drawsurf.surf->texturemins[1]; 307 308// << 16 components are to guarantee positive values for % 309 soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax; 310 basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) 311 + (tmax << 16)) % tmax) * twidth)]; 312 313 pcolumndest = r_drawsurf.surfdat; 314 315 for (u=0 ; u<r_numhblocks; u++) 316 { 317 r_lightptr = blocklights + u; 318 319 prowdestbase = pcolumndest; 320 321 pbasesource = basetptr + soffset; 322 323 (*pblockdrawer)(); 324 325 soffset = soffset + blocksize; 326 if (soffset >= smax) 327 soffset = 0; 328 329 pcolumndest += horzblockstep; 330 } 331} 332 333 334//============================================================================= 335 336#if !id386 337 338/* 339================ 340R_DrawSurfaceBlock8_mip0 341================ 342*/ 343void R_DrawSurfaceBlock8_mip0 (void) 344{ 345 int v, i, b, lightstep, lighttemp, light; 346 unsigned char pix, *psource, *prowdest; 347 348 psource = pbasesource; 349 prowdest = prowdestbase; 350 351 for (v=0 ; v<r_numvblocks ; v++) 352 { 353 // FIXME: make these locals? 354 // FIXME: use delta rather than both right and left, like ASM? 355 lightleft = r_lightptr[0]; 356 lightright = r_lightptr[1]; 357 r_lightptr += r_lightwidth; 358 lightleftstep = (r_lightptr[0] - lightleft) >> 4; 359 lightrightstep = (r_lightptr[1] - lightright) >> 4; 360 361 for (i=0 ; i<16 ; i++) 362 { 363 lighttemp = lightleft - lightright; 364 lightstep = lighttemp >> 4; 365 366 light = lightright; 367 368 for (b=15; b>=0; b--) 369 { 370 pix = psource[b]; 371 prowdest[b] = ((unsigned char *)vid.colormap) 372 [(light & 0xFF00) + pix]; 373 light += lightstep; 374 } 375 376 psource += sourcetstep; 377 lightright += lightrightstep; 378 lightleft += lightleftstep; 379 prowdest += surfrowbytes; 380 } 381 382 if (psource >= r_sourcemax) 383 psource -= r_stepback; 384 } 385} 386 387 388/* 389================ 390R_DrawSurfaceBlock8_mip1 391================ 392*/ 393void R_DrawSurfaceBlock8_mip1 (void) 394{ 395 int v, i, b, lightstep, lighttemp, light; 396 unsigned char pix, *psource, *prowdest; 397 398 psource = pbasesource; 399 prowdest = prowdestbase; 400 401 for (v=0 ; v<r_numvblocks ; v++) 402 { 403 // FIXME: make these locals? 404 // FIXME: use delta rather than both right and left, like ASM? 405 lightleft = r_lightptr[0]; 406 lightright = r_lightptr[1]; 407 r_lightptr += r_lightwidth; 408 lightleftstep = (r_lightptr[0] - lightleft) >> 3; 409 lightrightstep = (r_lightptr[1] - lightright) >> 3; 410 411 for (i=0 ; i<8 ; i++) 412 { 413 lighttemp = lightleft - lightright; 414 lightstep = lighttemp >> 3; 415 416 light = lightright; 417 418 for (b=7; b>=0; b--) 419 { 420 pix = psource[b]; 421 prowdest[b] = ((unsigned char *)vid.colormap) 422 [(light & 0xFF00) + pix]; 423 light += lightstep; 424 } 425 426 psource += sourcetstep; 427 lightright += lightrightstep; 428 lightleft += lightleftstep; 429 prowdest += surfrowbytes; 430 } 431 432 if (psource >= r_sourcemax) 433 psource -= r_stepback; 434 } 435} 436 437 438/* 439================ 440R_DrawSurfaceBlock8_mip2 441================ 442*/ 443void R_DrawSurfaceBlock8_mip2 (void) 444{ 445 int v, i, b, lightstep, lighttemp, light; 446 unsigned char pix, *psource, *prowdest; 447 448 psource = pbasesource; 449 prowdest = prowdestbase; 450 451 for (v=0 ; v<r_numvblocks ; v++) 452 { 453 // FIXME: make these locals? 454 // FIXME: use delta rather than both right and left, like ASM? 455 lightleft = r_lightptr[0]; 456 lightright = r_lightptr[1]; 457 r_lightptr += r_lightwidth; 458 lightleftstep = (r_lightptr[0] - lightleft) >> 2; 459 lightrightstep = (r_lightptr[1] - lightright) >> 2; 460 461 for (i=0 ; i<4 ; i++) 462 { 463 lighttemp = lightleft - lightright; 464 lightstep = lighttemp >> 2; 465 466 light = lightright; 467 468 for (b=3; b>=0; b--) 469 { 470 pix = psource[b]; 471 prowdest[b] = ((unsigned char *)vid.colormap) 472 [(light & 0xFF00) + pix]; 473 light += lightstep; 474 } 475 476 psource += sourcetstep; 477 lightright += lightrightstep; 478 lightleft += lightleftstep; 479 prowdest += surfrowbytes; 480 } 481 482 if (psource >= r_sourcemax) 483 psource -= r_stepback; 484 } 485} 486 487 488/* 489================ 490R_DrawSurfaceBlock8_mip3 491================ 492*/ 493void R_DrawSurfaceBlock8_mip3 (void) 494{ 495 int v, i, b, lightstep, lighttemp, light; 496 unsigned char pix, *psource, *prowdest; 497 498 psource = pbasesource; 499 prowdest = prowdestbase; 500 501 for (v=0 ; v<r_numvblocks ; v++) 502 { 503 // FIXME: make these locals? 504 // FIXME: use delta rather than both right and left, like ASM? 505 lightleft = r_lightptr[0]; 506 lightright = r_lightptr[1]; 507 r_lightptr += r_lightwidth; 508 lightleftstep = (r_lightptr[0] - lightleft) >> 1; 509 lightrightstep = (r_lightptr[1] - lightright) >> 1; 510 511 for (i=0 ; i<2 ; i++) 512 { 513 lighttemp = lightleft - lightright; 514 lightstep = lighttemp >> 1; 515 516 light = lightright; 517 518 for (b=1; b>=0; b--) 519 { 520 pix = psource[b]; 521 prowdest[b] = ((unsigned char *)vid.colormap) 522 [(light & 0xFF00) + pix]; 523 light += lightstep; 524 } 525 526 psource += sourcetstep; 527 lightright += lightrightstep; 528 lightleft += lightleftstep; 529 prowdest += surfrowbytes; 530 } 531 532 if (psource >= r_sourcemax) 533 psource -= r_stepback; 534 } 535} 536 537 538/* 539================ 540R_DrawSurfaceBlock16 541 542FIXME: make this work 543================ 544*/ 545void R_DrawSurfaceBlock16 (void) 546{ 547 int k; 548 unsigned char *psource; 549 int lighttemp, lightstep, light; 550 unsigned short *prowdest; 551 552 prowdest = (unsigned short *)prowdestbase; 553 554 for (k=0 ; k<blocksize ; k++) 555 { 556 unsigned short *pdest; 557 unsigned char pix; 558 int b; 559 560 psource = pbasesource; 561 lighttemp = lightright - lightleft; 562 lightstep = lighttemp >> blockdivshift; 563 564 light = lightleft; 565 pdest = prowdest; 566 567 for (b=0; b<blocksize; b++) 568 { 569 pix = *psource; 570 *pdest = vid.colormap16[(light & 0xFF00) + pix]; 571 psource += sourcesstep; 572 pdest++; 573 light += lightstep; 574 } 575 576 pbasesource += sourcetstep; 577 lightright += lightrightstep; 578 lightleft += lightleftstep; 579 prowdest = (unsigned short *)((long)prowdest + surfrowbytes); 580 } 581 582 prowdestbase = prowdest; 583} 584 585#endif 586 587 588//============================================================================ 589 590/* 591================ 592R_GenTurbTile 593================ 594*/ 595void R_GenTurbTile (pixel_t *pbasetex, void *pdest) 596{ 597 int *turb; 598 int i, j, s, t; 599 byte *pd; 600 601 turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); 602 pd = (byte *)pdest; 603 604 for (i=0 ; i<TILE_SIZE ; i++) 605 { 606 for (j=0 ; j<TILE_SIZE ; j++) 607 { 608 s = (((j << 16) + turb[i & (CYCLE-1)]) >> 16) & 63; 609 t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63; 610 *pd++ = *(pbasetex + (t<<6) + s); 611 } 612 } 613} 614 615 616/* 617================ 618R_GenTurbTile16 619================ 620*/ 621void R_GenTurbTile16 (pixel_t *pbasetex, void *pdest) 622{ 623 int *turb; 624 int i, j, s, t; 625 unsigned short *pd; 626 627 turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); 628 pd = (unsigned short *)pdest; 629 630 for (i=0 ; i<TILE_SIZE ; i++) 631 { 632 for (j=0 ; j<TILE_SIZE ; j++) 633 { 634 s = (((j << 16) + turb[i & (CYCLE-1)]) >> 16) & 63; 635 t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63; 636 *pd++ = d_8to16table[*(pbasetex + (t<<6) + s)]; 637 } 638 } 639} 640 641 642/* 643================ 644R_GenTile 645================ 646*/ 647void R_GenTile (msurface_t *psurf, void *pdest) 648{ 649 if (psurf->flags & SURF_DRAWTURB) 650 { 651 if (r_pixbytes == 1) 652 { 653 R_GenTurbTile ((pixel_t *) 654 ((byte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest); 655 } 656 else 657 { 658 R_GenTurbTile16 ((pixel_t *) 659 ((byte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest); 660 } 661 } 662 else if (psurf->flags & SURF_DRAWSKY) 663 { 664 if (r_pixbytes == 1) 665 { 666 R_GenSkyTile (pdest); 667 } 668 else 669 { 670 R_GenSkyTile16 (pdest); 671 } 672 } 673 else 674 { 675 Sys_Error ("Unknown tile type"); 676 } 677} 678 679