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
21// draw.c -- this is the only file outside the refresh that touches the
22// vid buffer
23
24#include "quakedef.h"
25
26typedef struct {
27	vrect_t	rect;
28	int		width;
29	int		height;
30	byte	*ptexbytes;
31	int		rowbytes;
32} rectdesc_t;
33
34static rectdesc_t	r_rectdesc;
35
36byte		*draw_chars;				// 8*8 graphic characters
37qpic_t		*draw_disc;
38qpic_t		*draw_backtile;
39
40//=============================================================================
41/* Support Routines */
42
43typedef struct cachepic_s
44{
45	char		name[MAX_QPATH];
46	cache_user_t	cache;
47} cachepic_t;
48
49#define	MAX_CACHED_PICS		128
50cachepic_t	menu_cachepics[MAX_CACHED_PICS];
51int			menu_numcachepics;
52
53
54qpic_t	*Draw_PicFromWad (char *name)
55{
56	return W_GetLumpName (name);
57}
58
59/*
60================
61Draw_CachePic
62================
63*/
64qpic_t	*Draw_CachePic (char *path)
65{
66	cachepic_t	*pic;
67	int			i;
68	qpic_t		*dat;
69
70	for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
71		if (!strcmp (path, pic->name))
72			break;
73
74	if (i == menu_numcachepics)
75	{
76		if (menu_numcachepics == MAX_CACHED_PICS)
77			Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
78		menu_numcachepics++;
79		strcpy (pic->name, path);
80	}
81
82	dat = Cache_Check (&pic->cache);
83
84	if (dat)
85		return dat;
86
87//
88// load the pic from disk
89//
90	COM_LoadCacheFile (path, &pic->cache);
91
92	dat = (qpic_t *)pic->cache.data;
93	if (!dat)
94	{
95		Sys_Error ("Draw_CachePic: failed to load %s", path);
96	}
97
98	SwapPic (dat);
99
100	return dat;
101}
102
103
104
105/*
106===============
107Draw_Init
108===============
109*/
110void Draw_Init (void)
111{
112	draw_chars = W_GetLumpName ("conchars");
113	draw_disc = W_GetLumpName ("disc");
114	draw_backtile = W_GetLumpName ("backtile");
115
116	r_rectdesc.width = draw_backtile->width;
117	r_rectdesc.height = draw_backtile->height;
118	r_rectdesc.ptexbytes = draw_backtile->data;
119	r_rectdesc.rowbytes = draw_backtile->width;
120}
121
122
123
124/*
125================
126Draw_Character
127
128Draws one 8*8 graphics character with 0 being transparent.
129It can be clipped to the top of the screen to allow the console to be
130smoothly scrolled off.
131================
132*/
133void Draw_Character (int x, int y, int num)
134{
135	byte			*dest;
136	byte			*source;
137	unsigned short	*pusdest;
138	int				drawline;
139	int				row, col;
140
141	num &= 255;
142
143	if (y <= -8)
144		return;			// totally off screen
145
146	if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
147		return;
148	if (num < 0 || num > 255)
149		return;
150
151	row = num>>4;
152	col = num&15;
153	source = draw_chars + (row<<10) + (col<<3);
154
155	if (y < 0)
156	{	// clipped
157		drawline = 8 + y;
158		source -= 128*y;
159		y = 0;
160	}
161	else
162		drawline = 8;
163
164
165	if (r_pixbytes == 1)
166	{
167		dest = vid.conbuffer + y*vid.conrowbytes + x;
168
169		while (drawline--)
170		{
171			if (source[0])
172				dest[0] = source[0];
173			if (source[1])
174				dest[1] = source[1];
175			if (source[2])
176				dest[2] = source[2];
177			if (source[3])
178				dest[3] = source[3];
179			if (source[4])
180				dest[4] = source[4];
181			if (source[5])
182				dest[5] = source[5];
183			if (source[6])
184				dest[6] = source[6];
185			if (source[7])
186				dest[7] = source[7];
187			source += 128;
188			dest += vid.conrowbytes;
189		}
190	}
191	else
192	{
193	// FIXME: pre-expand to native format?
194		pusdest = (unsigned short *)
195				((byte *)vid.conbuffer + y*vid.conrowbytes + (x<<1));
196
197		while (drawline--)
198		{
199			if (source[0])
200				pusdest[0] = d_8to16table[source[0]];
201			if (source[1])
202				pusdest[1] = d_8to16table[source[1]];
203			if (source[2])
204				pusdest[2] = d_8to16table[source[2]];
205			if (source[3])
206				pusdest[3] = d_8to16table[source[3]];
207			if (source[4])
208				pusdest[4] = d_8to16table[source[4]];
209			if (source[5])
210				pusdest[5] = d_8to16table[source[5]];
211			if (source[6])
212				pusdest[6] = d_8to16table[source[6]];
213			if (source[7])
214				pusdest[7] = d_8to16table[source[7]];
215
216			source += 128;
217			pusdest += (vid.conrowbytes >> 1);
218		}
219	}
220}
221
222/*
223================
224Draw_String
225================
226*/
227void Draw_String (int x, int y, char *str)
228{
229	while (*str)
230	{
231		Draw_Character (x, y, *str);
232		str++;
233		x += 8;
234	}
235}
236
237/*
238================
239Draw_Alt_String
240================
241*/
242void Draw_Alt_String (int x, int y, char *str)
243{
244	while (*str)
245	{
246		Draw_Character (x, y, (*str) | 0x80);
247		str++;
248		x += 8;
249	}
250}
251
252void Draw_Pixel(int x, int y, byte color)
253{
254	byte			*dest;
255	unsigned short	*pusdest;
256
257	if (r_pixbytes == 1)
258	{
259		dest = vid.conbuffer + y*vid.conrowbytes + x;
260		*dest = color;
261	}
262	else
263	{
264	// FIXME: pre-expand to native format?
265		pusdest = (unsigned short *)
266				((byte *)vid.conbuffer + y*vid.conrowbytes + (x<<1));
267		*pusdest = d_8to16table[color];
268	}
269}
270
271void Draw_Crosshair(void)
272{
273	int x, y;
274	extern cvar_t crosshair, cl_crossx, cl_crossy, crosshaircolor;
275	extern vrect_t		scr_vrect;
276	byte c = (byte)crosshaircolor.value;
277
278	if (crosshair.value == 2) {
279		x = scr_vrect.x + scr_vrect.width/2 + cl_crossx.value;
280		y = scr_vrect.y + scr_vrect.height/2 + cl_crossy.value;
281		Draw_Pixel(x - 1, y, c);
282		Draw_Pixel(x - 3, y, c);
283		Draw_Pixel(x + 1, y, c);
284		Draw_Pixel(x + 3, y, c);
285		Draw_Pixel(x, y - 1, c);
286		Draw_Pixel(x, y - 3, c);
287		Draw_Pixel(x, y + 1, c);
288		Draw_Pixel(x, y + 3, c);
289	} else if (crosshair.value)
290		Draw_Character (
291			scr_vrect.x + scr_vrect.width/2-4 + cl_crossx.value,
292			scr_vrect.y + scr_vrect.height/2-4 + cl_crossy.value,
293			'+');
294}
295
296/*
297================
298Draw_DebugChar
299
300Draws a single character directly to the upper right corner of the screen.
301This is for debugging lockups by drawing different chars in different parts
302of the code.
303================
304*/
305void Draw_DebugChar (char num)
306{
307	byte			*dest;
308	byte			*source;
309	int				drawline;
310	extern byte		*draw_chars;
311	int				row, col;
312
313	if (!vid.direct)
314		return;		// don't have direct FB access, so no debugchars...
315
316	drawline = 8;
317
318	row = num>>4;
319	col = num&15;
320	source = draw_chars + (row<<10) + (col<<3);
321
322	dest = vid.direct + 312;
323
324	while (drawline--)
325	{
326		dest[0] = source[0];
327		dest[1] = source[1];
328		dest[2] = source[2];
329		dest[3] = source[3];
330		dest[4] = source[4];
331		dest[5] = source[5];
332		dest[6] = source[6];
333		dest[7] = source[7];
334		source += 128;
335		dest += 320;
336	}
337}
338
339/*
340=============
341Draw_Pic
342=============
343*/
344void Draw_Pic (int x, int y, qpic_t *pic)
345{
346	byte			*dest, *source;
347	unsigned short	*pusdest;
348	int				v, u;
349
350	if ((x < 0) ||
351		(x + pic->width > vid.width) ||
352		(y < 0) ||
353		(y + pic->height > vid.height))
354	{
355		Sys_Error ("Draw_Pic: bad coordinates");
356	}
357
358	source = pic->data;
359
360	if (r_pixbytes == 1)
361	{
362		dest = vid.buffer + y * vid.rowbytes + x;
363
364		for (v=0 ; v<pic->height ; v++)
365		{
366			Q_memcpy (dest, source, pic->width);
367			dest += vid.rowbytes;
368			source += pic->width;
369		}
370	}
371	else
372	{
373	// FIXME: pretranslate at load time?
374		pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
375
376		for (v=0 ; v<pic->height ; v++)
377		{
378			for (u=0 ; u<pic->width ; u++)
379			{
380				pusdest[u] = d_8to16table[source[u]];
381			}
382
383			pusdest += vid.rowbytes >> 1;
384			source += pic->width;
385		}
386	}
387}
388
389
390/*
391=============
392Draw_SubPic
393=============
394*/
395void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height)
396{
397	byte			*dest, *source;
398	unsigned short	*pusdest;
399	int				v, u;
400
401	if ((x < 0) ||
402		(x + width > vid.width) ||
403		(y < 0) ||
404		(y + height > vid.height))
405	{
406		Sys_Error ("Draw_Pic: bad coordinates");
407	}
408
409	source = pic->data + srcy * pic->width + srcx;
410
411	if (r_pixbytes == 1)
412	{
413		dest = vid.buffer + y * vid.rowbytes + x;
414
415		for (v=0 ; v<height ; v++)
416		{
417			Q_memcpy (dest, source, width);
418			dest += vid.rowbytes;
419			source += pic->width;
420		}
421	}
422	else
423	{
424	// FIXME: pretranslate at load time?
425		pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
426
427		for (v=0 ; v<height ; v++)
428		{
429			for (u=srcx ; u<(srcx+width) ; u++)
430			{
431				pusdest[u] = d_8to16table[source[u]];
432			}
433
434			pusdest += vid.rowbytes >> 1;
435			source += pic->width;
436		}
437	}
438}
439
440
441/*
442=============
443Draw_TransPic
444=============
445*/
446void Draw_TransPic (int x, int y, qpic_t *pic)
447{
448	byte	*dest, *source, tbyte;
449	unsigned short	*pusdest;
450	int				v, u;
451
452	if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
453		 (unsigned)(y + pic->height) > vid.height)
454	{
455		Sys_Error ("Draw_TransPic: bad coordinates");
456	}
457
458	source = pic->data;
459
460	if (r_pixbytes == 1)
461	{
462		dest = vid.buffer + y * vid.rowbytes + x;
463
464		if (pic->width & 7)
465		{	// general
466			for (v=0 ; v<pic->height ; v++)
467			{
468				for (u=0 ; u<pic->width ; u++)
469					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
470						dest[u] = tbyte;
471
472				dest += vid.rowbytes;
473				source += pic->width;
474			}
475		}
476		else
477		{	// unwound
478			for (v=0 ; v<pic->height ; v++)
479			{
480				for (u=0 ; u<pic->width ; u+=8)
481				{
482					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
483						dest[u] = tbyte;
484					if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
485						dest[u+1] = tbyte;
486					if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
487						dest[u+2] = tbyte;
488					if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
489						dest[u+3] = tbyte;
490					if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
491						dest[u+4] = tbyte;
492					if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
493						dest[u+5] = tbyte;
494					if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
495						dest[u+6] = tbyte;
496					if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
497						dest[u+7] = tbyte;
498				}
499				dest += vid.rowbytes;
500				source += pic->width;
501			}
502		}
503	}
504	else
505	{
506	// FIXME: pretranslate at load time?
507		pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
508
509		for (v=0 ; v<pic->height ; v++)
510		{
511			for (u=0 ; u<pic->width ; u++)
512			{
513				tbyte = source[u];
514
515				if (tbyte != TRANSPARENT_COLOR)
516				{
517					pusdest[u] = d_8to16table[tbyte];
518				}
519			}
520
521			pusdest += vid.rowbytes >> 1;
522			source += pic->width;
523		}
524	}
525}
526
527
528/*
529=============
530Draw_TransPicTranslate
531=============
532*/
533void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
534{
535	byte	*dest, *source, tbyte;
536	unsigned short	*pusdest;
537	int				v, u;
538
539	if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
540		 (unsigned)(y + pic->height) > vid.height)
541	{
542		Sys_Error ("Draw_TransPic: bad coordinates");
543	}
544
545	source = pic->data;
546
547	if (r_pixbytes == 1)
548	{
549		dest = vid.buffer + y * vid.rowbytes + x;
550
551		if (pic->width & 7)
552		{	// general
553			for (v=0 ; v<pic->height ; v++)
554			{
555				for (u=0 ; u<pic->width ; u++)
556					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
557						dest[u] = translation[tbyte];
558
559				dest += vid.rowbytes;
560				source += pic->width;
561			}
562		}
563		else
564		{	// unwound
565			for (v=0 ; v<pic->height ; v++)
566			{
567				for (u=0 ; u<pic->width ; u+=8)
568				{
569					if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
570						dest[u] = translation[tbyte];
571					if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
572						dest[u+1] = translation[tbyte];
573					if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
574						dest[u+2] = translation[tbyte];
575					if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
576						dest[u+3] = translation[tbyte];
577					if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
578						dest[u+4] = translation[tbyte];
579					if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
580						dest[u+5] = translation[tbyte];
581					if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
582						dest[u+6] = translation[tbyte];
583					if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
584						dest[u+7] = translation[tbyte];
585				}
586				dest += vid.rowbytes;
587				source += pic->width;
588			}
589		}
590	}
591	else
592	{
593	// FIXME: pretranslate at load time?
594		pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
595
596		for (v=0 ; v<pic->height ; v++)
597		{
598			for (u=0 ; u<pic->width ; u++)
599			{
600				tbyte = source[u];
601
602				if (tbyte != TRANSPARENT_COLOR)
603				{
604					pusdest[u] = d_8to16table[tbyte];
605				}
606			}
607
608			pusdest += vid.rowbytes >> 1;
609			source += pic->width;
610		}
611	}
612}
613
614
615void Draw_CharToConback (int num, byte *dest)
616{
617	int		row, col;
618	byte	*source;
619	int		drawline;
620	int		x;
621
622	row = num>>4;
623	col = num&15;
624	source = draw_chars + (row<<10) + (col<<3);
625
626	drawline = 8;
627
628	while (drawline--)
629	{
630		for (x=0 ; x<8 ; x++)
631			if (source[x])
632				dest[x] = 0x60 + source[x];
633		source += 128;
634		dest += 320;
635	}
636
637}
638
639/*
640================
641Draw_ConsoleBackground
642
643================
644*/
645void Draw_ConsoleBackground (int lines)
646{
647	int				x, y, v;
648	byte			*src, *dest;
649	unsigned short	*pusdest;
650	int				f, fstep;
651	qpic_t			*conback;
652	char			ver[100];
653	static			char saveback[320*8];
654
655	conback = Draw_CachePic ("gfx/conback.lmp");
656
657// hack the version number directly into the pic
658
659	//sprintf (ver, "start commands with a \\ character %4.2f", VERSION);
660
661	if (cls.download) {
662		sprintf (ver, "%4.2f", VERSION);
663		dest = conback->data + 320 + 320*186 - 11 - 8*strlen(ver);
664	} else {
665#if defined(__linux__)
666		sprintf (ver, "Linux (%4.2f) QuakeWorld %4.2f", LINUX_VERSION, VERSION);
667#else
668		sprintf (ver, "QuakeWorld %4.2f", VERSION);
669#endif
670		dest = conback->data + 320 - (strlen(ver)*8 + 11) + 320*186;
671	}
672
673	memcpy(saveback, conback->data + 320*186, 320*8);
674	for (x=0 ; x<strlen(ver) ; x++)
675		Draw_CharToConback (ver[x], dest+(x<<3));
676
677// draw the pic
678	if (r_pixbytes == 1)
679	{
680		dest = vid.conbuffer;
681
682		for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
683		{
684			v = (vid.conheight - lines + y)*200/vid.conheight;
685			src = conback->data + v*320;
686			if (vid.conwidth == 320)
687				memcpy (dest, src, vid.conwidth);
688			else
689			{
690				f = 0;
691				fstep = 320*0x10000/vid.conwidth;
692				for (x=0 ; x<vid.conwidth ; x+=4)
693				{
694					dest[x] = src[f>>16];
695					f += fstep;
696					dest[x+1] = src[f>>16];
697					f += fstep;
698					dest[x+2] = src[f>>16];
699					f += fstep;
700					dest[x+3] = src[f>>16];
701					f += fstep;
702				}
703			}
704		}
705	}
706	else
707	{
708		pusdest = (unsigned short *)vid.conbuffer;
709
710		for (y=0 ; y<lines ; y++, pusdest += (vid.conrowbytes >> 1))
711		{
712		// FIXME: pre-expand to native format?
713		// FIXME: does the endian switching go away in production?
714			v = (vid.conheight - lines + y)*200/vid.conheight;
715			src = conback->data + v*320;
716			f = 0;
717			fstep = 320*0x10000/vid.conwidth;
718			for (x=0 ; x<vid.conwidth ; x+=4)
719			{
720				pusdest[x] = d_8to16table[src[f>>16]];
721				f += fstep;
722				pusdest[x+1] = d_8to16table[src[f>>16]];
723				f += fstep;
724				pusdest[x+2] = d_8to16table[src[f>>16]];
725				f += fstep;
726				pusdest[x+3] = d_8to16table[src[f>>16]];
727				f += fstep;
728			}
729		}
730	}
731	// put it back
732	memcpy(conback->data + 320*186, saveback, 320*8);
733}
734
735
736/*
737==============
738R_DrawRect8
739==============
740*/
741void R_DrawRect8 (vrect_t *prect, int rowbytes, byte *psrc,
742	int transparent)
743{
744	byte	t;
745	int		i, j, srcdelta, destdelta;
746	byte	*pdest;
747
748	pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x;
749
750	srcdelta = rowbytes - prect->width;
751	destdelta = vid.rowbytes - prect->width;
752
753	if (transparent)
754	{
755		for (i=0 ; i<prect->height ; i++)
756		{
757			for (j=0 ; j<prect->width ; j++)
758			{
759				t = *psrc;
760				if (t != TRANSPARENT_COLOR)
761				{
762					*pdest = t;
763				}
764
765				psrc++;
766				pdest++;
767			}
768
769			psrc += srcdelta;
770			pdest += destdelta;
771		}
772	}
773	else
774	{
775		for (i=0 ; i<prect->height ; i++)
776		{
777			memcpy (pdest, psrc, prect->width);
778			psrc += rowbytes;
779			pdest += vid.rowbytes;
780		}
781	}
782}
783
784
785/*
786==============
787R_DrawRect16
788==============
789*/
790void R_DrawRect16 (vrect_t *prect, int rowbytes, byte *psrc,
791	int transparent)
792{
793	byte			t;
794	int				i, j, srcdelta, destdelta;
795	unsigned short	*pdest;
796
797// FIXME: would it be better to pre-expand native-format versions?
798
799	pdest = (unsigned short *)vid.buffer +
800			(prect->y * (vid.rowbytes >> 1)) + prect->x;
801
802	srcdelta = rowbytes - prect->width;
803	destdelta = (vid.rowbytes >> 1) - prect->width;
804
805	if (transparent)
806	{
807		for (i=0 ; i<prect->height ; i++)
808		{
809			for (j=0 ; j<prect->width ; j++)
810			{
811				t = *psrc;
812				if (t != TRANSPARENT_COLOR)
813				{
814					*pdest = d_8to16table[t];
815				}
816
817				psrc++;
818				pdest++;
819			}
820
821			psrc += srcdelta;
822			pdest += destdelta;
823		}
824	}
825	else
826	{
827		for (i=0 ; i<prect->height ; i++)
828		{
829			for (j=0 ; j<prect->width ; j++)
830			{
831				*pdest = d_8to16table[*psrc];
832				psrc++;
833				pdest++;
834			}
835
836			psrc += srcdelta;
837			pdest += destdelta;
838		}
839	}
840}
841
842
843/*
844=============
845Draw_TileClear
846
847This repeats a 64*64 tile graphic to fill the screen around a sized down
848refresh window.
849=============
850*/
851void Draw_TileClear (int x, int y, int w, int h)
852{
853	int				width, height, tileoffsetx, tileoffsety;
854	byte			*psrc;
855	vrect_t			vr;
856
857	r_rectdesc.rect.x = x;
858	r_rectdesc.rect.y = y;
859	r_rectdesc.rect.width = w;
860	r_rectdesc.rect.height = h;
861
862	vr.y = r_rectdesc.rect.y;
863	height = r_rectdesc.rect.height;
864
865	tileoffsety = vr.y % r_rectdesc.height;
866
867	while (height > 0)
868	{
869		vr.x = r_rectdesc.rect.x;
870		width = r_rectdesc.rect.width;
871
872		if (tileoffsety != 0)
873			vr.height = r_rectdesc.height - tileoffsety;
874		else
875			vr.height = r_rectdesc.height;
876
877		if (vr.height > height)
878			vr.height = height;
879
880		tileoffsetx = vr.x % r_rectdesc.width;
881
882		while (width > 0)
883		{
884			if (tileoffsetx != 0)
885				vr.width = r_rectdesc.width - tileoffsetx;
886			else
887				vr.width = r_rectdesc.width;
888
889			if (vr.width > width)
890				vr.width = width;
891
892			psrc = r_rectdesc.ptexbytes +
893					(tileoffsety * r_rectdesc.rowbytes) + tileoffsetx;
894
895			if (r_pixbytes == 1)
896			{
897				R_DrawRect8 (&vr, r_rectdesc.rowbytes, psrc, 0);
898			}
899			else
900			{
901				R_DrawRect16 (&vr, r_rectdesc.rowbytes, psrc, 0);
902			}
903
904			vr.x += vr.width;
905			width -= vr.width;
906			tileoffsetx = 0;	// only the left tile can be left-clipped
907		}
908
909		vr.y += vr.height;
910		height -= vr.height;
911		tileoffsety = 0;		// only the top tile can be top-clipped
912	}
913}
914
915
916/*
917=============
918Draw_Fill
919
920Fills a box of pixels with a single color
921=============
922*/
923void Draw_Fill (int x, int y, int w, int h, int c)
924{
925	byte			*dest;
926	unsigned short	*pusdest;
927	unsigned		uc;
928	int				u, v;
929
930	if (x < 0 || x + w > vid.width ||
931		y < 0 || y + h > vid.height) {
932		Con_Printf("Bad Draw_Fill(%d, %d, %d, %d, %c)\n",
933			x, y, w, h, c);
934		return;
935	}
936
937	if (r_pixbytes == 1)
938	{
939		dest = vid.buffer + y*vid.rowbytes + x;
940		for (v=0 ; v<h ; v++, dest += vid.rowbytes)
941			for (u=0 ; u<w ; u++)
942				dest[u] = c;
943	}
944	else
945	{
946		uc = d_8to16table[c];
947
948		pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
949		for (v=0 ; v<h ; v++, pusdest += (vid.rowbytes >> 1))
950			for (u=0 ; u<w ; u++)
951				pusdest[u] = uc;
952	}
953}
954//=============================================================================
955
956/*
957================
958Draw_FadeScreen
959
960================
961*/
962void Draw_FadeScreen (void)
963{
964	int			x,y;
965	byte		*pbuf;
966
967	VID_UnlockBuffer ();
968	S_ExtraUpdate ();
969	VID_LockBuffer ();
970
971	for (y=0 ; y<vid.height ; y++)
972	{
973		int	t;
974
975		pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
976		t = (y & 1) << 1;
977
978		for (x=0 ; x<vid.width ; x++)
979		{
980			if ((x & 3) != t)
981				pbuf[x] = 0;
982		}
983	}
984
985	VID_UnlockBuffer ();
986	S_ExtraUpdate ();
987	VID_LockBuffer ();
988}
989
990//=============================================================================
991
992/*
993================
994Draw_BeginDisc
995
996Draws the little blue disc in the corner of the screen.
997Call before beginning any disc IO.
998================
999*/
1000void Draw_BeginDisc (void)
1001{
1002
1003	D_BeginDirectRect (vid.width - 24, 0, draw_disc->data, 24, 24);
1004}
1005
1006
1007/*
1008================
1009Draw_EndDisc
1010
1011Erases the disc icon.
1012Call after completing any disc IO
1013================
1014*/
1015void Draw_EndDisc (void)
1016{
1017
1018	D_EndDirectRect (vid.width - 24, 0, 24, 24);
1019}
1020
1021