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 blocklights[t*smax + s] += (rad - dist)*256;
120 }
121 }
122 }
123 }
124
125 /*
126 ===============
127 R_BuildLightMap
128
129 Combine and scale multiple lightmaps into the 8.8 format in blocklights
130 ===============
131 */
R_BuildLightMap(void)132 void 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 ===============
191 R_TextureAnimation
192
193 Returns the proper texture for a given time and base texture
194 ===============
195 */
R_TextureAnimation(texture_t * base)196 texture_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 ===============
228 R_DrawSurface
229 ===============
230 */
R_DrawSurface(void)231 void 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 ================
323 R_DrawSurfaceBlock8_mip0
324 ================
325 */
R_DrawSurfaceBlock8_mip0(void)326 void 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 ================
373 R_DrawSurfaceBlock8_mip1
374 ================
375 */
R_DrawSurfaceBlock8_mip1(void)376 void 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 ================
423 R_DrawSurfaceBlock8_mip2
424 ================
425 */
R_DrawSurfaceBlock8_mip2(void)426 void 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 ================
473 R_DrawSurfaceBlock8_mip3
474 ================
475 */
R_DrawSurfaceBlock8_mip3(void)476 void 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 ================
523 R_DrawSurfaceBlock16
524
525 FIXME: make this work
526 ================
527 */
R_DrawSurfaceBlock16(void)528 void 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 ================
575 R_GenTurbTile
576 ================
577 */
R_GenTurbTile(pixel_t * pbasetex,void * pdest)578 void 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 ================
601 R_GenTurbTile16
602 ================
603 */
R_GenTurbTile16(pixel_t * pbasetex,void * pdest)604 void 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 ================
627 R_GenTile
628 ================
629 */
R_GenTile(msurface_t * psurf,void * pdest)630 void 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