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