ID_CA.C (31762B)
1 // ID_CA.C 2 3 // this has been customized for WOLF 4 5 /* 6 ============================================================================= 7 8 Id Software Caching Manager 9 --------------------------- 10 11 Must be started BEFORE the memory manager, because it needs to get the headers 12 loaded into the data segment 13 14 ============================================================================= 15 */ 16 17 #include "ID_HEADS.H" 18 #pragma hdrstop 19 20 #pragma warn -pro 21 #pragma warn -use 22 23 #define THREEBYTEGRSTARTS 24 25 /* 26 ============================================================================= 27 28 LOCAL CONSTANTS 29 30 ============================================================================= 31 */ 32 33 typedef struct 34 { 35 unsigned bit0,bit1; // 0-255 is a character, > is a pointer to a node 36 } huffnode; 37 38 39 typedef struct 40 { 41 unsigned RLEWtag; 42 long headeroffsets[100]; 43 byte tileinfo[]; 44 } mapfiletype; 45 46 47 /* 48 ============================================================================= 49 50 GLOBAL VARIABLES 51 52 ============================================================================= 53 */ 54 55 byte _seg *tinf; 56 int mapon; 57 58 unsigned _seg *mapsegs[MAPPLANES]; 59 maptype _seg *mapheaderseg[NUMMAPS]; 60 byte _seg *audiosegs[NUMSNDCHUNKS]; 61 void _seg *grsegs[NUMCHUNKS]; 62 63 byte far grneeded[NUMCHUNKS]; 64 byte ca_levelbit,ca_levelnum; 65 66 int profilehandle,debughandle; 67 68 char audioname[13]="AUDIO."; 69 70 /* 71 ============================================================================= 72 73 LOCAL VARIABLES 74 75 ============================================================================= 76 */ 77 78 extern long far CGAhead; 79 extern long far EGAhead; 80 extern byte CGAdict; 81 extern byte EGAdict; 82 extern byte far maphead; 83 extern byte mapdict; 84 extern byte far audiohead; 85 extern byte audiodict; 86 87 88 char extension[5], // Need a string, not constant to change cache files 89 gheadname[10]=GREXT"HEAD.", 90 gfilename[10]=GREXT"GRAPH.", 91 gdictname[10]=GREXT"DICT.", 92 mheadname[10]="MAPHEAD.", 93 mfilename[10]="MAPTEMP.", 94 aheadname[10]="AUDIOHED.", 95 afilename[10]="AUDIOT."; 96 97 void CA_CannotOpen(char *string); 98 99 long _seg *grstarts; // array of offsets in egagraph, -1 for sparse 100 long _seg *audiostarts; // array of offsets in audio / audiot 101 102 #ifdef GRHEADERLINKED 103 huffnode *grhuffman; 104 #else 105 huffnode grhuffman[255]; 106 #endif 107 108 #ifdef AUDIOHEADERLINKED 109 huffnode *audiohuffman; 110 #else 111 huffnode audiohuffman[255]; 112 #endif 113 114 115 int grhandle; // handle to EGAGRAPH 116 int maphandle; // handle to MAPTEMP / GAMEMAPS 117 int audiohandle; // handle to AUDIOT / AUDIO 118 119 long chunkcomplen,chunkexplen; 120 121 SDMode oldsoundmode; 122 123 124 125 void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, 126 unsigned length); 127 128 129 #ifdef THREEBYTEGRSTARTS 130 #define FILEPOSSIZE 3 131 //#define GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff) 132 long GRFILEPOS(int c) 133 { 134 long value; 135 int offset; 136 137 offset = c*3; 138 139 value = *(long far *)(((byte far *)grstarts)+offset); 140 141 value &= 0x00ffffffl; 142 143 if (value == 0xffffffl) 144 value = -1; 145 146 return value; 147 }; 148 #else 149 #define FILEPOSSIZE 4 150 #define GRFILEPOS(c) (grstarts[c]) 151 #endif 152 153 /* 154 ============================================================================= 155 156 LOW LEVEL ROUTINES 157 158 ============================================================================= 159 */ 160 161 /* 162 ============================ 163 = 164 = CA_OpenDebug / CA_CloseDebug 165 = 166 = Opens a binary file with the handle "debughandle" 167 = 168 ============================ 169 */ 170 171 void CA_OpenDebug (void) 172 { 173 unlink ("DEBUG.TXT"); 174 debughandle = open("DEBUG.TXT", O_CREAT | O_WRONLY | O_TEXT); 175 } 176 177 void CA_CloseDebug (void) 178 { 179 close (debughandle); 180 } 181 182 183 184 /* 185 ============================ 186 = 187 = CAL_GetGrChunkLength 188 = 189 = Gets the length of an explicit length chunk (not tiles) 190 = The file pointer is positioned so the compressed data can be read in next. 191 = 192 ============================ 193 */ 194 195 void CAL_GetGrChunkLength (int chunk) 196 { 197 lseek(grhandle,GRFILEPOS(chunk),SEEK_SET); 198 read(grhandle,&chunkexplen,sizeof(chunkexplen)); 199 chunkcomplen = GRFILEPOS(chunk+1)-GRFILEPOS(chunk)-4; 200 } 201 202 203 /* 204 ========================== 205 = 206 = CA_FarRead 207 = 208 = Read from a file to a far pointer 209 = 210 ========================== 211 */ 212 213 boolean CA_FarRead (int handle, byte far *dest, long length) 214 { 215 if (length>0xffffl) 216 Quit ("CA_FarRead doesn't support 64K reads yet!"); 217 218 asm push ds 219 asm mov bx,[handle] 220 asm mov cx,[WORD PTR length] 221 asm mov dx,[WORD PTR dest] 222 asm mov ds,[WORD PTR dest+2] 223 asm mov ah,0x3f // READ w/handle 224 asm int 21h 225 asm pop ds 226 asm jnc good 227 errno = _AX; 228 return false; 229 good: 230 asm cmp ax,[WORD PTR length] 231 asm je done 232 errno = EINVFMT; // user manager knows this is bad read 233 return false; 234 done: 235 return true; 236 } 237 238 239 /* 240 ========================== 241 = 242 = CA_SegWrite 243 = 244 = Write from a file to a far pointer 245 = 246 ========================== 247 */ 248 249 boolean CA_FarWrite (int handle, byte far *source, long length) 250 { 251 if (length>0xffffl) 252 Quit ("CA_FarWrite doesn't support 64K reads yet!"); 253 254 asm push ds 255 asm mov bx,[handle] 256 asm mov cx,[WORD PTR length] 257 asm mov dx,[WORD PTR source] 258 asm mov ds,[WORD PTR source+2] 259 asm mov ah,0x40 // WRITE w/handle 260 asm int 21h 261 asm pop ds 262 asm jnc good 263 errno = _AX; 264 return false; 265 good: 266 asm cmp ax,[WORD PTR length] 267 asm je done 268 errno = ENOMEM; // user manager knows this is bad write 269 return false; 270 271 done: 272 return true; 273 } 274 275 276 /* 277 ========================== 278 = 279 = CA_ReadFile 280 = 281 = Reads a file into an allready allocated buffer 282 = 283 ========================== 284 */ 285 286 boolean CA_ReadFile (char *filename, memptr *ptr) 287 { 288 int handle; 289 long size; 290 291 if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1) 292 return false; 293 294 size = filelength (handle); 295 if (!CA_FarRead (handle,*ptr,size)) 296 { 297 close (handle); 298 return false; 299 } 300 close (handle); 301 return true; 302 } 303 304 305 /* 306 ========================== 307 = 308 = CA_WriteFile 309 = 310 = Writes a file from a memory buffer 311 = 312 ========================== 313 */ 314 315 boolean CA_WriteFile (char *filename, void far *ptr, long length) 316 { 317 int handle; 318 long size; 319 320 handle = open(filename,O_CREAT | O_BINARY | O_WRONLY, 321 S_IREAD | S_IWRITE | S_IFREG); 322 323 if (handle == -1) 324 return false; 325 326 if (!CA_FarWrite (handle,ptr,length)) 327 { 328 close (handle); 329 return false; 330 } 331 close (handle); 332 return true; 333 } 334 335 336 337 /* 338 ========================== 339 = 340 = CA_LoadFile 341 = 342 = Allocate space for and load a file 343 = 344 ========================== 345 */ 346 347 boolean CA_LoadFile (char *filename, memptr *ptr) 348 { 349 int handle; 350 long size; 351 352 if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1) 353 return false; 354 355 size = filelength (handle); 356 MM_GetPtr (ptr,size); 357 if (!CA_FarRead (handle,*ptr,size)) 358 { 359 close (handle); 360 return false; 361 } 362 close (handle); 363 return true; 364 } 365 366 /* 367 ============================================================================ 368 369 COMPRESSION routines, see JHUFF.C for more 370 371 ============================================================================ 372 */ 373 374 375 376 /* 377 =============== 378 = 379 = CAL_OptimizeNodes 380 = 381 = Goes through a huffman table and changes the 256-511 node numbers to the 382 = actular address of the node. Must be called before CAL_HuffExpand 383 = 384 =============== 385 */ 386 387 void CAL_OptimizeNodes (huffnode *table) 388 { 389 huffnode *node; 390 int i; 391 392 node = table; 393 394 for (i=0;i<255;i++) 395 { 396 if (node->bit0 >= 256) 397 node->bit0 = (unsigned)(table+(node->bit0-256)); 398 if (node->bit1 >= 256) 399 node->bit1 = (unsigned)(table+(node->bit1-256)); 400 node++; 401 } 402 } 403 404 405 406 /* 407 ====================== 408 = 409 = CAL_HuffExpand 410 = 411 = Length is the length of the EXPANDED data 412 = If screenhack, the data is decompressed in four planes directly 413 = to the screen 414 = 415 ====================== 416 */ 417 418 void CAL_HuffExpand (byte huge *source, byte huge *dest, 419 long length,huffnode *hufftable, boolean screenhack) 420 { 421 // unsigned bit,byte,node,code; 422 unsigned sourceseg,sourceoff,destseg,destoff,endoff; 423 huffnode *headptr; 424 byte mapmask; 425 // huffnode *nodeon; 426 427 headptr = hufftable+254; // head node is allways node 254 428 429 source++; // normalize 430 source--; 431 dest++; 432 dest--; 433 434 if (screenhack) 435 { 436 mapmask = 1; 437 asm mov dx,SC_INDEX 438 asm mov ax,SC_MAPMASK + 256 439 asm out dx,ax 440 length >>= 2; 441 } 442 443 sourceseg = FP_SEG(source); 444 sourceoff = FP_OFF(source); 445 destseg = FP_SEG(dest); 446 destoff = FP_OFF(dest); 447 endoff = destoff+length; 448 449 // 450 // ds:si source 451 // es:di dest 452 // ss:bx node pointer 453 // 454 455 if (length <0xfff0) 456 { 457 458 //-------------------------- 459 // expand less than 64k of data 460 //-------------------------- 461 462 asm mov bx,[headptr] 463 464 asm mov si,[sourceoff] 465 asm mov di,[destoff] 466 asm mov es,[destseg] 467 asm mov ds,[sourceseg] 468 asm mov ax,[endoff] 469 470 asm mov ch,[si] // load first byte 471 asm inc si 472 asm mov cl,1 473 474 expandshort: 475 asm test ch,cl // bit set? 476 asm jnz bit1short 477 asm mov dx,[ss:bx] // take bit0 path from node 478 asm shl cl,1 // advance to next bit position 479 asm jc newbyteshort 480 asm jnc sourceupshort 481 482 bit1short: 483 asm mov dx,[ss:bx+2] // take bit1 path 484 asm shl cl,1 // advance to next bit position 485 asm jnc sourceupshort 486 487 newbyteshort: 488 asm mov ch,[si] // load next byte 489 asm inc si 490 asm mov cl,1 // back to first bit 491 492 sourceupshort: 493 asm or dh,dh // if dx<256 its a byte, else move node 494 asm jz storebyteshort 495 asm mov bx,dx // next node = (huffnode *)code 496 asm jmp expandshort 497 498 storebyteshort: 499 asm mov [es:di],dl 500 asm inc di // write a decopmpressed byte out 501 asm mov bx,[headptr] // back to the head node for next bit 502 503 asm cmp di,ax // done? 504 asm jne expandshort 505 506 // 507 // perform screenhack if needed 508 // 509 asm test [screenhack],1 510 asm jz notscreen 511 asm shl [mapmask],1 512 asm mov ah,[mapmask] 513 asm cmp ah,16 514 asm je notscreen // all four planes done 515 asm mov dx,SC_INDEX 516 asm mov al,SC_MAPMASK 517 asm out dx,ax 518 asm mov di,[destoff] 519 asm mov ax,[endoff] 520 asm jmp expandshort 521 522 notscreen:; 523 } 524 else 525 { 526 527 //-------------------------- 528 // expand more than 64k of data 529 //-------------------------- 530 531 length--; 532 533 asm mov bx,[headptr] 534 asm mov cl,1 535 536 asm mov si,[sourceoff] 537 asm mov di,[destoff] 538 asm mov es,[destseg] 539 asm mov ds,[sourceseg] 540 541 asm lodsb // load first byte 542 543 expand: 544 asm test al,cl // bit set? 545 asm jnz bit1 546 asm mov dx,[ss:bx] // take bit0 path from node 547 asm jmp gotcode 548 bit1: 549 asm mov dx,[ss:bx+2] // take bit1 path 550 551 gotcode: 552 asm shl cl,1 // advance to next bit position 553 asm jnc sourceup 554 asm lodsb 555 asm cmp si,0x10 // normalize ds:si 556 asm jb sinorm 557 asm mov cx,ds 558 asm inc cx 559 asm mov ds,cx 560 asm xor si,si 561 sinorm: 562 asm mov cl,1 // back to first bit 563 564 sourceup: 565 asm or dh,dh // if dx<256 its a byte, else move node 566 asm jz storebyte 567 asm mov bx,dx // next node = (huffnode *)code 568 asm jmp expand 569 570 storebyte: 571 asm mov [es:di],dl 572 asm inc di // write a decopmpressed byte out 573 asm mov bx,[headptr] // back to the head node for next bit 574 575 asm cmp di,0x10 // normalize es:di 576 asm jb dinorm 577 asm mov dx,es 578 asm inc dx 579 asm mov es,dx 580 asm xor di,di 581 dinorm: 582 583 asm sub [WORD PTR ss:length],1 584 asm jnc expand 585 asm dec [WORD PTR ss:length+2] 586 asm jns expand // when length = ffff ffff, done 587 588 } 589 590 asm mov ax,ss 591 asm mov ds,ax 592 593 } 594 595 596 /* 597 ====================== 598 = 599 = CAL_CarmackExpand 600 = 601 = Length is the length of the EXPANDED data 602 = 603 ====================== 604 */ 605 606 #define NEARTAG 0xa7 607 #define FARTAG 0xa8 608 609 void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length) 610 { 611 unsigned ch,chhigh,count,offset; 612 unsigned far *copyptr, far *inptr, far *outptr; 613 614 length/=2; 615 616 inptr = source; 617 outptr = dest; 618 619 while (length) 620 { 621 ch = *inptr++; 622 chhigh = ch>>8; 623 if (chhigh == NEARTAG) 624 { 625 count = ch&0xff; 626 if (!count) 627 { // have to insert a word containing the tag byte 628 ch |= *((unsigned char far *)inptr)++; 629 *outptr++ = ch; 630 length--; 631 } 632 else 633 { 634 offset = *((unsigned char far *)inptr)++; 635 copyptr = outptr - offset; 636 length -= count; 637 while (count--) 638 *outptr++ = *copyptr++; 639 } 640 } 641 else if (chhigh == FARTAG) 642 { 643 count = ch&0xff; 644 if (!count) 645 { // have to insert a word containing the tag byte 646 ch |= *((unsigned char far *)inptr)++; 647 *outptr++ = ch; 648 length --; 649 } 650 else 651 { 652 offset = *inptr++; 653 copyptr = dest + offset; 654 length -= count; 655 while (count--) 656 *outptr++ = *copyptr++; 657 } 658 } 659 else 660 { 661 *outptr++ = ch; 662 length --; 663 } 664 } 665 } 666 667 668 669 /* 670 ====================== 671 = 672 = CA_RLEWcompress 673 = 674 ====================== 675 */ 676 677 long CA_RLEWCompress (unsigned huge *source, long length, unsigned huge *dest, 678 unsigned rlewtag) 679 { 680 long complength; 681 unsigned value,count,i; 682 unsigned huge *start,huge *end; 683 684 start = dest; 685 686 end = source + (length+1)/2; 687 688 // 689 // compress it 690 // 691 do 692 { 693 count = 1; 694 value = *source++; 695 while (*source == value && source<end) 696 { 697 count++; 698 source++; 699 } 700 if (count>3 || value == rlewtag) 701 { 702 // 703 // send a tag / count / value string 704 // 705 *dest++ = rlewtag; 706 *dest++ = count; 707 *dest++ = value; 708 } 709 else 710 { 711 // 712 // send word without compressing 713 // 714 for (i=1;i<=count;i++) 715 *dest++ = value; 716 } 717 718 } while (source<end); 719 720 complength = 2*(dest-start); 721 return complength; 722 } 723 724 725 /* 726 ====================== 727 = 728 = CA_RLEWexpand 729 = length is EXPANDED length 730 = 731 ====================== 732 */ 733 734 void CA_RLEWexpand (unsigned huge *source, unsigned huge *dest,long length, 735 unsigned rlewtag) 736 { 737 // unsigned value,count,i; 738 unsigned huge *end; 739 unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff; 740 741 742 // 743 // expand it 744 // 745 #if 0 746 do 747 { 748 value = *source++; 749 if (value != rlewtag) 750 // 751 // uncompressed 752 // 753 *dest++=value; 754 else 755 { 756 // 757 // compressed string 758 // 759 count = *source++; 760 value = *source++; 761 for (i=1;i<=count;i++) 762 *dest++ = value; 763 } 764 } while (dest<end); 765 #endif 766 767 end = dest + (length)/2; 768 sourceseg = FP_SEG(source); 769 sourceoff = FP_OFF(source); 770 destseg = FP_SEG(dest); 771 destoff = FP_OFF(dest); 772 endseg = FP_SEG(end); 773 endoff = FP_OFF(end); 774 775 776 // 777 // ax = source value 778 // bx = tag value 779 // cx = repeat counts 780 // dx = scratch 781 // 782 // NOTE: A repeat count that produces 0xfff0 bytes can blow this! 783 // 784 785 asm mov bx,rlewtag 786 asm mov si,sourceoff 787 asm mov di,destoff 788 asm mov es,destseg 789 asm mov ds,sourceseg 790 791 expand: 792 asm lodsw 793 asm cmp ax,bx 794 asm je repeat 795 asm stosw 796 asm jmp next 797 798 repeat: 799 asm lodsw 800 asm mov cx,ax // repeat count 801 asm lodsw // repeat value 802 asm rep stosw 803 804 next: 805 806 asm cmp si,0x10 // normalize ds:si 807 asm jb sinorm 808 asm mov ax,si 809 asm shr ax,1 810 asm shr ax,1 811 asm shr ax,1 812 asm shr ax,1 813 asm mov dx,ds 814 asm add dx,ax 815 asm mov ds,dx 816 asm and si,0xf 817 sinorm: 818 asm cmp di,0x10 // normalize es:di 819 asm jb dinorm 820 asm mov ax,di 821 asm shr ax,1 822 asm shr ax,1 823 asm shr ax,1 824 asm shr ax,1 825 asm mov dx,es 826 asm add dx,ax 827 asm mov es,dx 828 asm and di,0xf 829 dinorm: 830 831 asm cmp di,ss:endoff 832 asm jne expand 833 asm mov ax,es 834 asm cmp ax,ss:endseg 835 asm jb expand 836 837 asm mov ax,ss 838 asm mov ds,ax 839 840 } 841 842 843 844 /* 845 ============================================================================= 846 847 CACHE MANAGER ROUTINES 848 849 ============================================================================= 850 */ 851 852 853 /* 854 ====================== 855 = 856 = CAL_SetupGrFile 857 = 858 ====================== 859 */ 860 861 void CAL_SetupGrFile (void) 862 { 863 char fname[13]; 864 int handle; 865 memptr compseg; 866 867 #ifdef GRHEADERLINKED 868 869 grhuffman = (huffnode *)&EGAdict; 870 grstarts = (long _seg *)FP_SEG(&EGAhead); 871 872 CAL_OptimizeNodes (grhuffman); 873 874 #else 875 876 // 877 // load ???dict.ext (huffman dictionary for graphics files) 878 // 879 880 strcpy(fname,gdictname); 881 strcat(fname,extension); 882 883 if ((handle = open(fname, 884 O_RDONLY | O_BINARY, S_IREAD)) == -1) 885 CA_CannotOpen(fname); 886 887 read(handle, &grhuffman, sizeof(grhuffman)); 888 close(handle); 889 CAL_OptimizeNodes (grhuffman); 890 // 891 // load the data offsets from ???head.ext 892 // 893 MM_GetPtr (&(memptr)grstarts,(NUMCHUNKS+1)*FILEPOSSIZE); 894 895 strcpy(fname,gheadname); 896 strcat(fname,extension); 897 898 if ((handle = open(fname, 899 O_RDONLY | O_BINARY, S_IREAD)) == -1) 900 CA_CannotOpen(fname); 901 902 CA_FarRead(handle, (memptr)grstarts, (NUMCHUNKS+1)*FILEPOSSIZE); 903 904 close(handle); 905 906 907 #endif 908 909 // 910 // Open the graphics file, leaving it open until the game is finished 911 // 912 strcpy(fname,gfilename); 913 strcat(fname,extension); 914 915 grhandle = open(fname, O_RDONLY | O_BINARY); 916 if (grhandle == -1) 917 CA_CannotOpen(fname); 918 919 920 // 921 // load the pic and sprite headers into the arrays in the data segment 922 // 923 MM_GetPtr(&(memptr)pictable,NUMPICS*sizeof(pictabletype)); 924 CAL_GetGrChunkLength(STRUCTPIC); // position file pointer 925 MM_GetPtr(&compseg,chunkcomplen); 926 CA_FarRead (grhandle,compseg,chunkcomplen); 927 CAL_HuffExpand (compseg, (byte huge *)pictable,NUMPICS*sizeof(pictabletype),grhuffman,false); 928 MM_FreePtr(&compseg); 929 } 930 931 //========================================================================== 932 933 934 /* 935 ====================== 936 = 937 = CAL_SetupMapFile 938 = 939 ====================== 940 */ 941 942 void CAL_SetupMapFile (void) 943 { 944 int i; 945 int handle; 946 long length,pos; 947 char fname[13]; 948 949 // 950 // load maphead.ext (offsets and tileinfo for map file) 951 // 952 #ifndef MAPHEADERLINKED 953 strcpy(fname,mheadname); 954 strcat(fname,extension); 955 956 if ((handle = open(fname, 957 O_RDONLY | O_BINARY, S_IREAD)) == -1) 958 CA_CannotOpen(fname); 959 960 length = filelength(handle); 961 MM_GetPtr (&(memptr)tinf,length); 962 CA_FarRead(handle, tinf, length); 963 close(handle); 964 #else 965 966 tinf = (byte _seg *)FP_SEG(&maphead); 967 968 #endif 969 970 // 971 // open the data file 972 // 973 #ifdef CARMACIZED 974 strcpy(fname,"GAMEMAPS."); 975 strcat(fname,extension); 976 977 if ((maphandle = open(fname, 978 O_RDONLY | O_BINARY, S_IREAD)) == -1) 979 CA_CannotOpen(fname); 980 #else 981 strcpy(fname,mfilename); 982 strcat(fname,extension); 983 984 if ((maphandle = open(fname, 985 O_RDONLY | O_BINARY, S_IREAD)) == -1) 986 CA_CannotOpen(fname); 987 #endif 988 989 // 990 // load all map header 991 // 992 for (i=0;i<NUMMAPS;i++) 993 { 994 pos = ((mapfiletype _seg *)tinf)->headeroffsets[i]; 995 if (pos<0) // $FFFFFFFF start is a sparse map 996 continue; 997 998 MM_GetPtr(&(memptr)mapheaderseg[i],sizeof(maptype)); 999 MM_SetLock(&(memptr)mapheaderseg[i],true); 1000 lseek(maphandle,pos,SEEK_SET); 1001 CA_FarRead (maphandle,(memptr)mapheaderseg[i],sizeof(maptype)); 1002 } 1003 1004 // 1005 // allocate space for 3 64*64 planes 1006 // 1007 for (i=0;i<MAPPLANES;i++) 1008 { 1009 MM_GetPtr (&(memptr)mapsegs[i],64*64*2); 1010 MM_SetLock (&(memptr)mapsegs[i],true); 1011 } 1012 } 1013 1014 1015 //========================================================================== 1016 1017 1018 /* 1019 ====================== 1020 = 1021 = CAL_SetupAudioFile 1022 = 1023 ====================== 1024 */ 1025 1026 void CAL_SetupAudioFile (void) 1027 { 1028 int handle; 1029 long length; 1030 char fname[13]; 1031 1032 // 1033 // load maphead.ext (offsets and tileinfo for map file) 1034 // 1035 #ifndef AUDIOHEADERLINKED 1036 strcpy(fname,aheadname); 1037 strcat(fname,extension); 1038 1039 if ((handle = open(fname, 1040 O_RDONLY | O_BINARY, S_IREAD)) == -1) 1041 CA_CannotOpen(fname); 1042 1043 length = filelength(handle); 1044 MM_GetPtr (&(memptr)audiostarts,length); 1045 CA_FarRead(handle, (byte far *)audiostarts, length); 1046 close(handle); 1047 #else 1048 audiohuffman = (huffnode *)&audiodict; 1049 CAL_OptimizeNodes (audiohuffman); 1050 audiostarts = (long _seg *)FP_SEG(&audiohead); 1051 #endif 1052 1053 // 1054 // open the data file 1055 // 1056 #ifndef AUDIOHEADERLINKED 1057 strcpy(fname,afilename); 1058 strcat(fname,extension); 1059 1060 if ((audiohandle = open(fname, 1061 O_RDONLY | O_BINARY, S_IREAD)) == -1) 1062 CA_CannotOpen(fname); 1063 #else 1064 if ((audiohandle = open("AUDIO."EXTENSION, 1065 O_RDONLY | O_BINARY, S_IREAD)) == -1) 1066 Quit ("Can't open AUDIO."EXTENSION"!"); 1067 #endif 1068 } 1069 1070 //========================================================================== 1071 1072 1073 /* 1074 ====================== 1075 = 1076 = CA_Startup 1077 = 1078 = Open all files and load in headers 1079 = 1080 ====================== 1081 */ 1082 1083 void CA_Startup (void) 1084 { 1085 #ifdef PROFILE 1086 unlink ("PROFILE.TXT"); 1087 profilehandle = open("PROFILE.TXT", O_CREAT | O_WRONLY | O_TEXT); 1088 #endif 1089 1090 CAL_SetupMapFile (); 1091 CAL_SetupGrFile (); 1092 CAL_SetupAudioFile (); 1093 1094 mapon = -1; 1095 ca_levelbit = 1; 1096 ca_levelnum = 0; 1097 1098 } 1099 1100 //========================================================================== 1101 1102 1103 /* 1104 ====================== 1105 = 1106 = CA_Shutdown 1107 = 1108 = Closes all files 1109 = 1110 ====================== 1111 */ 1112 1113 void CA_Shutdown (void) 1114 { 1115 #ifdef PROFILE 1116 close (profilehandle); 1117 #endif 1118 1119 close (maphandle); 1120 close (grhandle); 1121 close (audiohandle); 1122 } 1123 1124 //=========================================================================== 1125 1126 /* 1127 ====================== 1128 = 1129 = CA_CacheAudioChunk 1130 = 1131 ====================== 1132 */ 1133 1134 void CA_CacheAudioChunk (int chunk) 1135 { 1136 long pos,compressed; 1137 #ifdef AUDIOHEADERLINKED 1138 long expanded; 1139 memptr bigbufferseg; 1140 byte far *source; 1141 #endif 1142 1143 if (audiosegs[chunk]) 1144 { 1145 MM_SetPurge (&(memptr)audiosegs[chunk],0); 1146 return; // allready in memory 1147 } 1148 1149 // 1150 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate 1151 // a larger buffer 1152 // 1153 pos = audiostarts[chunk]; 1154 compressed = audiostarts[chunk+1]-pos; 1155 1156 lseek(audiohandle,pos,SEEK_SET); 1157 1158 #ifndef AUDIOHEADERLINKED 1159 1160 MM_GetPtr (&(memptr)audiosegs[chunk],compressed); 1161 if (mmerror) 1162 return; 1163 1164 CA_FarRead(audiohandle,audiosegs[chunk],compressed); 1165 1166 #else 1167 1168 if (compressed<=BUFFERSIZE) 1169 { 1170 CA_FarRead(audiohandle,bufferseg,compressed); 1171 source = bufferseg; 1172 } 1173 else 1174 { 1175 MM_GetPtr(&bigbufferseg,compressed); 1176 if (mmerror) 1177 return; 1178 MM_SetLock (&bigbufferseg,true); 1179 CA_FarRead(audiohandle,bigbufferseg,compressed); 1180 source = bigbufferseg; 1181 } 1182 1183 expanded = *(long far *)source; 1184 source += 4; // skip over length 1185 MM_GetPtr (&(memptr)audiosegs[chunk],expanded); 1186 if (mmerror) 1187 goto done; 1188 CAL_HuffExpand (source,audiosegs[chunk],expanded,audiohuffman,false); 1189 1190 done: 1191 if (compressed>BUFFERSIZE) 1192 MM_FreePtr(&bigbufferseg); 1193 #endif 1194 } 1195 1196 //=========================================================================== 1197 1198 /* 1199 ====================== 1200 = 1201 = CA_LoadAllSounds 1202 = 1203 = Purges all sounds, then loads all new ones (mode switch) 1204 = 1205 ====================== 1206 */ 1207 1208 void CA_LoadAllSounds (void) 1209 { 1210 unsigned start,i; 1211 1212 switch (oldsoundmode) 1213 { 1214 case sdm_Off: 1215 goto cachein; 1216 case sdm_PC: 1217 start = STARTPCSOUNDS; 1218 break; 1219 case sdm_AdLib: 1220 start = STARTADLIBSOUNDS; 1221 break; 1222 } 1223 1224 for (i=0;i<NUMSOUNDS;i++,start++) 1225 if (audiosegs[start]) 1226 MM_SetPurge (&(memptr)audiosegs[start],3); // make purgable 1227 1228 cachein: 1229 1230 switch (SoundMode) 1231 { 1232 case sdm_Off: 1233 return; 1234 case sdm_PC: 1235 start = STARTPCSOUNDS; 1236 break; 1237 case sdm_AdLib: 1238 start = STARTADLIBSOUNDS; 1239 break; 1240 } 1241 1242 for (i=0;i<NUMSOUNDS;i++,start++) 1243 CA_CacheAudioChunk (start); 1244 1245 oldsoundmode = SoundMode; 1246 } 1247 1248 //=========================================================================== 1249 1250 1251 /* 1252 ====================== 1253 = 1254 = CAL_ExpandGrChunk 1255 = 1256 = Does whatever is needed with a pointer to a compressed chunk 1257 = 1258 ====================== 1259 */ 1260 1261 void CAL_ExpandGrChunk (int chunk, byte far *source) 1262 { 1263 long expanded; 1264 1265 1266 if (chunk >= STARTTILE8 && chunk < STARTEXTERNS) 1267 { 1268 // 1269 // expanded sizes of tile8/16/32 are implicit 1270 // 1271 1272 #define BLOCK 64 1273 #define MASKBLOCK 128 1274 1275 if (chunk<STARTTILE8M) // tile 8s are all in one chunk! 1276 expanded = BLOCK*NUMTILE8; 1277 else if (chunk<STARTTILE16) 1278 expanded = MASKBLOCK*NUMTILE8M; 1279 else if (chunk<STARTTILE16M) // all other tiles are one/chunk 1280 expanded = BLOCK*4; 1281 else if (chunk<STARTTILE32) 1282 expanded = MASKBLOCK*4; 1283 else if (chunk<STARTTILE32M) 1284 expanded = BLOCK*16; 1285 else 1286 expanded = MASKBLOCK*16; 1287 } 1288 else 1289 { 1290 // 1291 // everything else has an explicit size longword 1292 // 1293 expanded = *(long far *)source; 1294 source += 4; // skip over length 1295 } 1296 1297 // 1298 // allocate final space, decompress it, and free bigbuffer 1299 // Sprites need to have shifts made and various other junk 1300 // 1301 MM_GetPtr (&grsegs[chunk],expanded); 1302 if (mmerror) 1303 return; 1304 CAL_HuffExpand (source,grsegs[chunk],expanded,grhuffman,false); 1305 } 1306 1307 1308 /* 1309 ====================== 1310 = 1311 = CA_CacheGrChunk 1312 = 1313 = Makes sure a given chunk is in memory, loadiing it if needed 1314 = 1315 ====================== 1316 */ 1317 1318 void CA_CacheGrChunk (int chunk) 1319 { 1320 long pos,compressed; 1321 memptr bigbufferseg; 1322 byte far *source; 1323 int next; 1324 1325 grneeded[chunk] |= ca_levelbit; // make sure it doesn't get removed 1326 if (grsegs[chunk]) 1327 { 1328 MM_SetPurge (&grsegs[chunk],0); 1329 return; // allready in memory 1330 } 1331 1332 // 1333 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate 1334 // a larger buffer 1335 // 1336 pos = GRFILEPOS(chunk); 1337 if (pos<0) // $FFFFFFFF start is a sparse tile 1338 return; 1339 1340 next = chunk +1; 1341 while (GRFILEPOS(next) == -1) // skip past any sparse tiles 1342 next++; 1343 1344 compressed = GRFILEPOS(next)-pos; 1345 1346 lseek(grhandle,pos,SEEK_SET); 1347 1348 if (compressed<=BUFFERSIZE) 1349 { 1350 CA_FarRead(grhandle,bufferseg,compressed); 1351 source = bufferseg; 1352 } 1353 else 1354 { 1355 MM_GetPtr(&bigbufferseg,compressed); 1356 MM_SetLock (&bigbufferseg,true); 1357 CA_FarRead(grhandle,bigbufferseg,compressed); 1358 source = bigbufferseg; 1359 } 1360 1361 CAL_ExpandGrChunk (chunk,source); 1362 1363 if (compressed>BUFFERSIZE) 1364 MM_FreePtr(&bigbufferseg); 1365 } 1366 1367 1368 1369 //========================================================================== 1370 1371 /* 1372 ====================== 1373 = 1374 = CA_CacheScreen 1375 = 1376 = Decompresses a chunk from disk straight onto the screen 1377 = 1378 ====================== 1379 */ 1380 1381 void CA_CacheScreen (int chunk) 1382 { 1383 long pos,compressed,expanded; 1384 memptr bigbufferseg; 1385 byte far *source; 1386 int next; 1387 1388 // 1389 // load the chunk into a buffer 1390 // 1391 pos = GRFILEPOS(chunk); 1392 next = chunk +1; 1393 while (GRFILEPOS(next) == -1) // skip past any sparse tiles 1394 next++; 1395 compressed = GRFILEPOS(next)-pos; 1396 1397 lseek(grhandle,pos,SEEK_SET); 1398 1399 MM_GetPtr(&bigbufferseg,compressed); 1400 MM_SetLock (&bigbufferseg,true); 1401 CA_FarRead(grhandle,bigbufferseg,compressed); 1402 source = bigbufferseg; 1403 1404 expanded = *(long far *)source; 1405 source += 4; // skip over length 1406 1407 // 1408 // allocate final space, decompress it, and free bigbuffer 1409 // Sprites need to have shifts made and various other junk 1410 // 1411 CAL_HuffExpand (source,MK_FP(SCREENSEG,bufferofs),expanded,grhuffman,true); 1412 VW_MarkUpdateBlock (0,0,319,199); 1413 MM_FreePtr(&bigbufferseg); 1414 } 1415 1416 //========================================================================== 1417 1418 /* 1419 ====================== 1420 = 1421 = CA_CacheMap 1422 = 1423 = WOLF: This is specialized for a 64*64 map size 1424 = 1425 ====================== 1426 */ 1427 1428 void CA_CacheMap (int mapnum) 1429 { 1430 long pos,compressed; 1431 int plane; 1432 memptr *dest,bigbufferseg; 1433 unsigned size; 1434 unsigned far *source; 1435 #ifdef CARMACIZED 1436 memptr buffer2seg; 1437 long expanded; 1438 #endif 1439 1440 mapon = mapnum; 1441 1442 // 1443 // load the planes into the allready allocated buffers 1444 // 1445 size = 64*64*2; 1446 1447 for (plane = 0; plane<MAPPLANES; plane++) 1448 { 1449 pos = mapheaderseg[mapnum]->planestart[plane]; 1450 compressed = mapheaderseg[mapnum]->planelength[plane]; 1451 1452 dest = &(memptr)mapsegs[plane]; 1453 1454 lseek(maphandle,pos,SEEK_SET); 1455 if (compressed<=BUFFERSIZE) 1456 source = bufferseg; 1457 else 1458 { 1459 MM_GetPtr(&bigbufferseg,compressed); 1460 MM_SetLock (&bigbufferseg,true); 1461 source = bigbufferseg; 1462 } 1463 1464 CA_FarRead(maphandle,(byte far *)source,compressed); 1465 #ifdef CARMACIZED 1466 // 1467 // unhuffman, then unRLEW 1468 // The huffman'd chunk has a two byte expanded length first 1469 // The resulting RLEW chunk also does, even though it's not really 1470 // needed 1471 // 1472 expanded = *source; 1473 source++; 1474 MM_GetPtr (&buffer2seg,expanded); 1475 CAL_CarmackExpand (source, (unsigned far *)buffer2seg,expanded); 1476 CA_RLEWexpand (((unsigned far *)buffer2seg)+1,*dest,size, 1477 ((mapfiletype _seg *)tinf)->RLEWtag); 1478 MM_FreePtr (&buffer2seg); 1479 1480 #else 1481 // 1482 // unRLEW, skipping expanded length 1483 // 1484 CA_RLEWexpand (source+1, *dest,size, 1485 ((mapfiletype _seg *)tinf)->RLEWtag); 1486 #endif 1487 1488 if (compressed>BUFFERSIZE) 1489 MM_FreePtr(&bigbufferseg); 1490 } 1491 } 1492 1493 //=========================================================================== 1494 1495 /* 1496 ====================== 1497 = 1498 = CA_UpLevel 1499 = 1500 = Goes up a bit level in the needed lists and clears it out. 1501 = Everything is made purgable 1502 = 1503 ====================== 1504 */ 1505 1506 void CA_UpLevel (void) 1507 { 1508 int i; 1509 1510 if (ca_levelnum==7) 1511 Quit ("CA_UpLevel: Up past level 7!"); 1512 1513 for (i=0;i<NUMCHUNKS;i++) 1514 if (grsegs[i]) 1515 MM_SetPurge (&(memptr)grsegs[i],3); 1516 ca_levelbit<<=1; 1517 ca_levelnum++; 1518 } 1519 1520 //=========================================================================== 1521 1522 /* 1523 ====================== 1524 = 1525 = CA_DownLevel 1526 = 1527 = Goes down a bit level in the needed lists and recaches 1528 = everything from the lower level 1529 = 1530 ====================== 1531 */ 1532 1533 void CA_DownLevel (void) 1534 { 1535 if (!ca_levelnum) 1536 Quit ("CA_DownLevel: Down past level 0!"); 1537 ca_levelbit>>=1; 1538 ca_levelnum--; 1539 CA_CacheMarks(); 1540 } 1541 1542 //=========================================================================== 1543 1544 /* 1545 ====================== 1546 = 1547 = CA_ClearMarks 1548 = 1549 = Clears out all the marks at the current level 1550 = 1551 ====================== 1552 */ 1553 1554 void CA_ClearMarks (void) 1555 { 1556 int i; 1557 1558 for (i=0;i<NUMCHUNKS;i++) 1559 grneeded[i]&=~ca_levelbit; 1560 } 1561 1562 1563 //=========================================================================== 1564 1565 /* 1566 ====================== 1567 = 1568 = CA_ClearAllMarks 1569 = 1570 = Clears out all the marks on all the levels 1571 = 1572 ====================== 1573 */ 1574 1575 void CA_ClearAllMarks (void) 1576 { 1577 _fmemset (grneeded,0,sizeof(grneeded)); 1578 ca_levelbit = 1; 1579 ca_levelnum = 0; 1580 } 1581 1582 1583 //=========================================================================== 1584 1585 1586 /* 1587 ====================== 1588 = 1589 = CA_FreeGraphics 1590 = 1591 ====================== 1592 */ 1593 1594 1595 void CA_SetGrPurge (void) 1596 { 1597 int i; 1598 1599 // 1600 // free graphics 1601 // 1602 CA_ClearMarks (); 1603 1604 for (i=0;i<NUMCHUNKS;i++) 1605 if (grsegs[i]) 1606 MM_SetPurge (&(memptr)grsegs[i],3); 1607 } 1608 1609 1610 1611 /* 1612 ====================== 1613 = 1614 = CA_SetAllPurge 1615 = 1616 = Make everything possible purgable 1617 = 1618 ====================== 1619 */ 1620 1621 void CA_SetAllPurge (void) 1622 { 1623 int i; 1624 1625 1626 // 1627 // free sounds 1628 // 1629 for (i=0;i<NUMSNDCHUNKS;i++) 1630 if (audiosegs[i]) 1631 MM_SetPurge (&(memptr)audiosegs[i],3); 1632 1633 // 1634 // free graphics 1635 // 1636 CA_SetGrPurge (); 1637 } 1638 1639 1640 //=========================================================================== 1641 1642 /* 1643 ====================== 1644 = 1645 = CA_CacheMarks 1646 = 1647 ====================== 1648 */ 1649 #define MAXEMPTYREAD 1024 1650 1651 void CA_CacheMarks (void) 1652 { 1653 int i,next,numcache; 1654 long pos,endpos,nextpos,nextendpos,compressed; 1655 long bufferstart,bufferend; // file position of general buffer 1656 byte far *source; 1657 memptr bigbufferseg; 1658 1659 numcache = 0; 1660 // 1661 // go through and make everything not needed purgable 1662 // 1663 for (i=0;i<NUMCHUNKS;i++) 1664 if (grneeded[i]&ca_levelbit) 1665 { 1666 if (grsegs[i]) // its allready in memory, make 1667 MM_SetPurge(&grsegs[i],0); // sure it stays there! 1668 else 1669 numcache++; 1670 } 1671 else 1672 { 1673 if (grsegs[i]) // not needed, so make it purgeable 1674 MM_SetPurge(&grsegs[i],3); 1675 } 1676 1677 if (!numcache) // nothing to cache! 1678 return; 1679 1680 1681 // 1682 // go through and load in anything still needed 1683 // 1684 bufferstart = bufferend = 0; // nothing good in buffer now 1685 1686 for (i=0;i<NUMCHUNKS;i++) 1687 if ( (grneeded[i]&ca_levelbit) && !grsegs[i]) 1688 { 1689 pos = GRFILEPOS(i); 1690 if (pos<0) 1691 continue; 1692 1693 next = i +1; 1694 while (GRFILEPOS(next) == -1) // skip past any sparse tiles 1695 next++; 1696 1697 compressed = GRFILEPOS(next)-pos; 1698 endpos = pos+compressed; 1699 1700 if (compressed<=BUFFERSIZE) 1701 { 1702 if (bufferstart<=pos 1703 && bufferend>= endpos) 1704 { 1705 // data is allready in buffer 1706 source = (byte _seg *)bufferseg+(pos-bufferstart); 1707 } 1708 else 1709 { 1710 // load buffer with a new block from disk 1711 // try to get as many of the needed blocks in as possible 1712 while ( next < NUMCHUNKS ) 1713 { 1714 while (next < NUMCHUNKS && 1715 !(grneeded[next]&ca_levelbit && !grsegs[next])) 1716 next++; 1717 if (next == NUMCHUNKS) 1718 continue; 1719 1720 nextpos = GRFILEPOS(next); 1721 while (GRFILEPOS(++next) == -1) // skip past any sparse tiles 1722 ; 1723 nextendpos = GRFILEPOS(next); 1724 if (nextpos - endpos <= MAXEMPTYREAD 1725 && nextendpos-pos <= BUFFERSIZE) 1726 endpos = nextendpos; 1727 else 1728 next = NUMCHUNKS; // read pos to posend 1729 } 1730 1731 lseek(grhandle,pos,SEEK_SET); 1732 CA_FarRead(grhandle,bufferseg,endpos-pos); 1733 bufferstart = pos; 1734 bufferend = endpos; 1735 source = bufferseg; 1736 } 1737 } 1738 else 1739 { 1740 // big chunk, allocate temporary buffer 1741 MM_GetPtr(&bigbufferseg,compressed); 1742 if (mmerror) 1743 return; 1744 MM_SetLock (&bigbufferseg,true); 1745 lseek(grhandle,pos,SEEK_SET); 1746 CA_FarRead(grhandle,bigbufferseg,compressed); 1747 source = bigbufferseg; 1748 } 1749 1750 CAL_ExpandGrChunk (i,source); 1751 if (mmerror) 1752 return; 1753 1754 if (compressed>BUFFERSIZE) 1755 MM_FreePtr(&bigbufferseg); 1756 1757 } 1758 } 1759 1760 void CA_CannotOpen(char *string) 1761 { 1762 char str[30]; 1763 1764 strcpy(str,"Can't open "); 1765 strcat(str,string); 1766 strcat(str,"!\n"); 1767 Quit (str); 1768 }