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