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_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23 #include "r_local.h"
24
25 drawsurf_t r_drawsurf;
26
27 int lightleft, sourcesstep, blocksize, sourcetstep;
28 int lightdelta, lightdeltastep;
29 int lightright, lightleftstep, lightrightstep, blockdivshift;
30 unsigned blockdivmask;
31 void *prowdestbase;
32 unsigned char *pbasesource;
33 int surfrowbytes; // used by ASM files
34 unsigned *r_lightptr;
35 int r_stepback;
36 int r_lightwidth;
37 int r_numhblocks, r_numvblocks;
38 unsigned char *r_source, *r_sourcemax;
39
40 void R_DrawSurfaceBlock8_mip0 (void);
41 void R_DrawSurfaceBlock8_mip1 (void);
42 void R_DrawSurfaceBlock8_mip2 (void);
43 void R_DrawSurfaceBlock8_mip3 (void);
44
45 static void (*surfmiptable[4])(void) = {
46 R_DrawSurfaceBlock8_mip0,
47 R_DrawSurfaceBlock8_mip1,
48 R_DrawSurfaceBlock8_mip2,
49 R_DrawSurfaceBlock8_mip3
50 };
51
52
53
54 unsigned blocklights[18*18];
55
56 /*
57 ===============
58 R_AddDynamicLights
59 ===============
60 */
R_AddDynamicLights(void)61 void 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 ===============
144 R_BuildLightMap
145
146 Combine and scale multiple lightmaps into the 8.8 format in blocklights
147 ===============
148 */
R_BuildLightMap(void)149 void 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 ===============
208 R_TextureAnimation
209
210 Returns the proper texture for a given time and base texture
211 ===============
212 */
R_TextureAnimation(texture_t * base)213 texture_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 ===============
245 R_DrawSurface
246 ===============
247 */
R_DrawSurface(void)248 void 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 ================
340 R_DrawSurfaceBlock8_mip0
341 ================
342 */
R_DrawSurfaceBlock8_mip0(void)343 void 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 ================
390 R_DrawSurfaceBlock8_mip1
391 ================
392 */
R_DrawSurfaceBlock8_mip1(void)393 void 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 ================
440 R_DrawSurfaceBlock8_mip2
441 ================
442 */
R_DrawSurfaceBlock8_mip2(void)443 void 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 ================
490 R_DrawSurfaceBlock8_mip3
491 ================
492 */
R_DrawSurfaceBlock8_mip3(void)493 void 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 ================
540 R_DrawSurfaceBlock16
541
542 FIXME: make this work
543 ================
544 */
R_DrawSurfaceBlock16(void)545 void 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 ================
592 R_GenTurbTile
593 ================
594 */
R_GenTurbTile(pixel_t * pbasetex,void * pdest)595 void 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 ================
618 R_GenTurbTile16
619 ================
620 */
R_GenTurbTile16(pixel_t * pbasetex,void * pdest)621 void 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 ================
644 R_GenTile
645 ================
646 */
R_GenTile(msurface_t * psurf,void * pdest)647 void 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