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