]> 4ch.mooo.com Git - 16.git/blob - 16/keen456/KEEN4-6/ID_CA.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / ID_CA.C
1 /* Reconstructed Commander Keen 4-6 Source Code\r
2  * Copyright (C) 2021 K1n9_Duk3\r
3  *\r
4  * This file is primarily based on:\r
5  * Catacomb 3-D Source Code\r
6  * Copyright (C) 1993-2014 Flat Rock Software\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License along\r
19  * with this program; if not, write to the Free Software Foundation, Inc.,\r
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
21  */\r
22 \r
23 // ID_CA.C\r
24 \r
25 /*\r
26 =============================================================================\r
27 \r
28 Id Software Caching Manager\r
29 ---------------------------\r
30 \r
31 Must be started BEFORE the memory manager, because it needs to get the headers\r
32 loaded into the data segment\r
33 \r
34 =============================================================================\r
35 */\r
36 \r
37 #include "ID_HEADS.H"\r
38 #pragma hdrstop\r
39 \r
40 #pragma warn -pro\r
41 #pragma warn -use\r
42 \r
43 #define THREEBYTEGRSTARTS\r
44 \r
45 /*\r
46 =============================================================================\r
47 \r
48                                                  LOCAL CONSTANTS\r
49 \r
50 =============================================================================\r
51 */\r
52 \r
53 typedef struct\r
54 {\r
55   unsigned bit0,bit1;   // 0-255 is a character, > is a pointer to a node\r
56 } huffnode;\r
57 \r
58 \r
59 typedef struct\r
60 {\r
61         unsigned        RLEWtag;\r
62         long            headeroffsets[100];\r
63         byte            tileinfo[];\r
64 } mapfiletype;\r
65 \r
66 \r
67 /*\r
68 =============================================================================\r
69 \r
70                                                  GLOBAL VARIABLES\r
71 \r
72 =============================================================================\r
73 */\r
74 \r
75 byte            _seg    *tinf;\r
76 int                     mapon;\r
77 \r
78 unsigned        _seg    *mapsegs[3];\r
79 maptype         _seg    *mapheaderseg[NUMMAPS];\r
80 byte            _seg    *audiosegs[NUMSNDCHUNKS];\r
81 void            _seg    *grsegs[NUMCHUNKS];\r
82 \r
83 byte            far     grneeded[NUMCHUNKS];\r
84 byte            ca_levelbit,ca_levelnum;\r
85 \r
86 int                     profilehandle,debughandle;\r
87 \r
88 void    (*drawcachebox)         (char *title, unsigned numcache);\r
89 void    (*updatecachebox)       (void);\r
90 void    (*finishcachebox)       (void);\r
91 \r
92 /*\r
93 =============================================================================\r
94 \r
95                                                  LOCAL VARIABLES\r
96 \r
97 =============================================================================\r
98 */\r
99 \r
100 extern  long    far     CGAhead;\r
101 extern  long    far     EGAhead;\r
102 extern  byte    CGAdict;\r
103 extern  byte    EGAdict;\r
104 extern  byte    far     maphead;\r
105 extern  byte    mapdict;\r
106 extern  byte    far     audiohead;\r
107 extern  byte    audiodict;\r
108 \r
109 \r
110 long            _seg *grstarts; // array of offsets in egagraph, -1 for sparse\r
111 long            _seg *audiostarts;      // array of offsets in audio / audiot\r
112 \r
113 #ifdef GRHEADERLINKED\r
114 huffnode        *grhuffman;\r
115 #else\r
116 huffnode        grhuffman[255];\r
117 #endif\r
118 \r
119 #ifdef AUDIOHEADERLINKED\r
120 huffnode        *audiohuffman;\r
121 #else\r
122 huffnode        audiohuffman[255];\r
123 #endif\r
124 \r
125 \r
126 int                     grhandle;               // handle to EGAGRAPH\r
127 int                     maphandle;              // handle to MAPTEMP / GAMEMAPS\r
128 int                     audiohandle;    // handle to AUDIOT / AUDIO\r
129 \r
130 long            chunkcomplen,chunkexplen;\r
131 \r
132 SDMode          oldsoundmode;\r
133 \r
134 \r
135 \r
136 void    CAL_DialogDraw (char *title,unsigned numcache);\r
137 void    CAL_DialogUpdate (void);\r
138 void    CAL_DialogFinish (void);\r
139 void    CAL_CarmackExpand (unsigned far *source, unsigned far *dest,\r
140                 unsigned length);\r
141 \r
142 \r
143 #ifdef THREEBYTEGRSTARTS\r
144 #define FILEPOSSIZE     3\r
145 //#define       GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff)\r
146 long GRFILEPOS(int c)\r
147 {\r
148         long value;\r
149         int     offset;\r
150 \r
151         offset = c*3;\r
152 \r
153         value = *(long far *)(((byte far *)grstarts)+offset);\r
154 \r
155         value &= 0x00ffffffl;\r
156 \r
157         if (value == 0xffffffl)\r
158                 value = -1;\r
159 \r
160         return value;\r
161 };\r
162 #else\r
163 #define FILEPOSSIZE     4\r
164 #define GRFILEPOS(c) (grstarts[c])\r
165 #endif\r
166 \r
167 /*\r
168 =============================================================================\r
169 \r
170                                            LOW LEVEL ROUTINES\r
171 \r
172 =============================================================================\r
173 */\r
174 \r
175 /*\r
176 ============================\r
177 =\r
178 = CA_OpenDebug / CA_CloseDebug\r
179 =\r
180 = Opens a binary file with the handle "debughandle"\r
181 =\r
182 ============================\r
183 */\r
184 \r
185 void CA_OpenDebug (void)\r
186 {\r
187         unlink ("DEBUG.TXT");\r
188         debughandle = open("DEBUG.TXT", O_CREAT | O_WRONLY | O_TEXT);\r
189 }\r
190 \r
191 void CA_CloseDebug (void)\r
192 {\r
193         close (debughandle);\r
194 }\r
195 \r
196 \r
197 \r
198 /*\r
199 ============================\r
200 =\r
201 = CAL_GetGrChunkLength\r
202 =\r
203 = Gets the length of an explicit length chunk (not tiles)\r
204 = The file pointer is positioned so the compressed data can be read in next.\r
205 =\r
206 ============================\r
207 */\r
208 \r
209 void CAL_GetGrChunkLength (int chunk)\r
210 {\r
211         lseek(grhandle,GRFILEPOS(chunk),SEEK_SET);\r
212         read(grhandle,&chunkexplen,sizeof(chunkexplen));\r
213         chunkcomplen = GRFILEPOS(chunk+1)-GRFILEPOS(chunk)-4;\r
214 }\r
215 \r
216 \r
217 /*\r
218 ==========================\r
219 =\r
220 = CA_FarRead\r
221 =\r
222 = Read from a file to a far pointer\r
223 =\r
224 ==========================\r
225 */\r
226 \r
227 boolean CA_FarRead (int handle, byte far *dest, long length)\r
228 {\r
229         if (length>0xffffl)\r
230                 Quit ("CA_FarRead doesn't support 64K reads yet!");\r
231 \r
232 asm             push    ds\r
233 asm             mov     bx,[handle]\r
234 asm             mov     cx,[WORD PTR length]\r
235 asm             mov     dx,[WORD PTR dest]\r
236 asm             mov     ds,[WORD PTR dest+2]\r
237 asm             mov     ah,0x3f                         // READ w/handle\r
238 asm             int     21h\r
239 asm             pop     ds\r
240 asm             jnc     good\r
241         errno = _AX;\r
242         return  false;\r
243 good:\r
244 asm             cmp     ax,[WORD PTR length]\r
245 asm             je      done\r
246         errno = EINVFMT;                        // user manager knows this is bad read\r
247         return  false;\r
248 done:\r
249         return  true;\r
250 }\r
251 \r
252 \r
253 /*\r
254 ==========================\r
255 =\r
256 = CA_SegWrite\r
257 =\r
258 = Write from a file to a far pointer\r
259 =\r
260 ==========================\r
261 */\r
262 \r
263 boolean CA_FarWrite (int handle, byte far *source, long length)\r
264 {\r
265         if (length>0xffffl)\r
266                 Quit ("CA_FarWrite doesn't support 64K reads yet!");\r
267 \r
268 asm             push    ds\r
269 asm             mov     bx,[handle]\r
270 asm             mov     cx,[WORD PTR length]\r
271 asm             mov     dx,[WORD PTR source]\r
272 asm             mov     ds,[WORD PTR source+2]\r
273 asm             mov     ah,0x40                 // WRITE w/handle\r
274 asm             int     21h\r
275 asm             pop     ds\r
276 asm             jnc     good\r
277         errno = _AX;\r
278         return  false;\r
279 good:\r
280 asm             cmp     ax,[WORD PTR length]\r
281 asm             je      done\r
282         errno = ENOMEM;                         // user manager knows this is bad write\r
283         return  false;\r
284 \r
285 done:\r
286         return  true;\r
287 }\r
288 \r
289 \r
290 /*\r
291 ==========================\r
292 =\r
293 = CA_ReadFile\r
294 =\r
295 = Reads a file into an allready allocated buffer\r
296 =\r
297 ==========================\r
298 */\r
299 \r
300 boolean CA_ReadFile (char *filename, memptr *ptr)\r
301 {\r
302         int handle;\r
303         long size;\r
304 \r
305         if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
306                 return false;\r
307 \r
308         size = filelength (handle);\r
309         if (!CA_FarRead (handle,*ptr,size))\r
310         {\r
311                 close (handle);\r
312                 return false;\r
313         }\r
314         close (handle);\r
315         return true;\r
316 }\r
317 \r
318 \r
319 \r
320 /*\r
321 ==========================\r
322 =\r
323 = CA_LoadFile\r
324 =\r
325 = Allocate space for and load a file\r
326 =\r
327 ==========================\r
328 */\r
329 \r
330 boolean CA_LoadFile (char *filename, memptr *ptr)\r
331 {\r
332         int handle;\r
333         long size;\r
334 \r
335         if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
336                 return false;\r
337 \r
338         size = filelength (handle);\r
339         MM_GetPtr (ptr,size);\r
340         if (!CA_FarRead (handle,*ptr,size))\r
341         {\r
342                 close (handle);\r
343                 return false;\r
344         }\r
345         close (handle);\r
346         return true;\r
347 }\r
348 \r
349 /*\r
350 ============================================================================\r
351 \r
352                 COMPRESSION routines, see JHUFF.C for more\r
353 \r
354 ============================================================================\r
355 */\r
356 \r
357 \r
358 \r
359 /*\r
360 ===============\r
361 =\r
362 = CAL_OptimizeNodes\r
363 =\r
364 = Goes through a huffman table and changes the 256-511 node numbers to the\r
365 = actular address of the node.  Must be called before CAL_HuffExpand\r
366 =\r
367 ===============\r
368 */\r
369 \r
370 void CAL_OptimizeNodes (huffnode *table)\r
371 {\r
372   huffnode *node;\r
373   int i;\r
374 \r
375   node = table;\r
376 \r
377   for (i=0;i<255;i++)\r
378   {\r
379         if (node->bit0 >= 256)\r
380           node->bit0 = (unsigned)(table+(node->bit0-256));\r
381         if (node->bit1 >= 256)\r
382           node->bit1 = (unsigned)(table+(node->bit1-256));\r
383         node++;\r
384   }\r
385 }\r
386 \r
387 \r
388 \r
389 /*\r
390 ======================\r
391 =\r
392 = CAL_HuffExpand\r
393 =\r
394 = Length is the length of the EXPANDED data\r
395 =\r
396 ======================\r
397 */\r
398 \r
399 void CAL_HuffExpand (byte huge *source, byte huge *dest,\r
400   long length,huffnode *hufftable)\r
401 {\r
402 //  unsigned bit,byte,node,code;\r
403   unsigned sourceseg,sourceoff,destseg,destoff,endoff;\r
404   huffnode *headptr;\r
405 //  huffnode *nodeon;\r
406 \r
407   headptr = hufftable+254;      // head node is allways node 254\r
408 \r
409   source++;     // normalize\r
410   source--;\r
411   dest++;\r
412   dest--;\r
413 \r
414   sourceseg = FP_SEG(source);\r
415   sourceoff = FP_OFF(source);\r
416   destseg = FP_SEG(dest);\r
417   destoff = FP_OFF(dest);\r
418   endoff = destoff+length;\r
419 \r
420 //\r
421 // ds:si source\r
422 // es:di dest\r
423 // ss:bx node pointer\r
424 //\r
425 \r
426         if (length <0xfff0)\r
427         {\r
428 \r
429 //--------------------------\r
430 // expand less than 64k of data\r
431 //--------------------------\r
432 \r
433 asm mov bx,[headptr]\r
434 \r
435 asm     mov     si,[sourceoff]\r
436 asm     mov     di,[destoff]\r
437 asm     mov     es,[destseg]\r
438 asm     mov     ds,[sourceseg]\r
439 asm     mov     ax,[endoff]\r
440 \r
441 asm     mov     ch,[si]                         // load first byte\r
442 asm     inc     si\r
443 asm     mov     cl,1\r
444 \r
445 expandshort:\r
446 asm     test    ch,cl                   // bit set?\r
447 asm     jnz     bit1short\r
448 asm     mov     dx,[ss:bx]                      // take bit0 path from node\r
449 asm     shl     cl,1                            // advance to next bit position\r
450 asm     jc      newbyteshort\r
451 asm     jnc     sourceupshort\r
452 \r
453 bit1short:\r
454 asm     mov     dx,[ss:bx+2]            // take bit1 path\r
455 asm     shl     cl,1                            // advance to next bit position\r
456 asm     jnc     sourceupshort\r
457 \r
458 newbyteshort:\r
459 asm     mov     ch,[si]                         // load next byte\r
460 asm     inc     si\r
461 asm     mov     cl,1                            // back to first bit\r
462 \r
463 sourceupshort:\r
464 asm     or      dh,dh                           // if dx<256 its a byte, else move node\r
465 asm     jz      storebyteshort\r
466 asm     mov     bx,dx                           // next node = (huffnode *)code\r
467 asm     jmp     expandshort\r
468 \r
469 storebyteshort:\r
470 asm     mov     [es:di],dl\r
471 asm     inc     di                                      // write a decopmpressed byte out\r
472 asm     mov     bx,[headptr]            // back to the head node for next bit\r
473 \r
474 asm     cmp     di,ax                           // done?\r
475 asm     jne     expandshort\r
476         }\r
477         else\r
478         {\r
479 \r
480 //--------------------------\r
481 // expand more than 64k of data\r
482 //--------------------------\r
483 \r
484   length--;\r
485 \r
486 asm mov bx,[headptr]\r
487 asm     mov     cl,1\r
488 \r
489 asm     mov     si,[sourceoff]\r
490 asm     mov     di,[destoff]\r
491 asm     mov     es,[destseg]\r
492 asm     mov     ds,[sourceseg]\r
493 \r
494 asm     lodsb                   // load first byte\r
495 \r
496 expand:\r
497 asm     test    al,cl           // bit set?\r
498 asm     jnz     bit1\r
499 asm     mov     dx,[ss:bx]      // take bit0 path from node\r
500 asm     jmp     gotcode\r
501 bit1:\r
502 asm     mov     dx,[ss:bx+2]    // take bit1 path\r
503 \r
504 gotcode:\r
505 asm     shl     cl,1            // advance to next bit position\r
506 asm     jnc     sourceup\r
507 asm     lodsb\r
508 asm     cmp     si,0x10         // normalize ds:si\r
509 asm     jb      sinorm\r
510 asm     mov     cx,ds\r
511 asm     inc     cx\r
512 asm     mov     ds,cx\r
513 asm     xor     si,si\r
514 sinorm:\r
515 asm     mov     cl,1            // back to first bit\r
516 \r
517 sourceup:\r
518 asm     or      dh,dh           // if dx<256 its a byte, else move node\r
519 asm     jz      storebyte\r
520 asm     mov     bx,dx           // next node = (huffnode *)code\r
521 asm     jmp     expand\r
522 \r
523 storebyte:\r
524 asm     mov     [es:di],dl\r
525 asm     inc     di              // write a decopmpressed byte out\r
526 asm     mov     bx,[headptr]    // back to the head node for next bit\r
527 \r
528 asm     cmp     di,0x10         // normalize es:di\r
529 asm     jb      dinorm\r
530 asm     mov     dx,es\r
531 asm     inc     dx\r
532 asm     mov     es,dx\r
533 asm     xor     di,di\r
534 dinorm:\r
535 \r
536 asm     sub     [WORD PTR ss:length],1\r
537 asm     jnc     expand\r
538 asm     dec     [WORD PTR ss:length+2]\r
539 asm     jns     expand          // when length = ffff ffff, done\r
540 \r
541         }\r
542 \r
543 asm     mov     ax,ss\r
544 asm     mov     ds,ax\r
545 \r
546 }\r
547 \r
548 \r
549 /*\r
550 ======================\r
551 =\r
552 = CAL_CarmackExpand\r
553 =\r
554 = Length is the length of the EXPANDED data\r
555 =\r
556 ======================\r
557 */\r
558 \r
559 #define NEARTAG 0xa7\r
560 #define FARTAG  0xa8\r
561 \r
562 void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length)\r
563 {\r
564         unsigned        ch,chhigh,count,offset;\r
565         unsigned        far *copyptr, far *inptr, far *outptr;\r
566 \r
567         length/=2;\r
568 \r
569         inptr = source;\r
570         outptr = dest;\r
571 \r
572         while (length)\r
573         {\r
574                 ch = *inptr++;\r
575                 chhigh = ch>>8;\r
576                 if (chhigh == NEARTAG)\r
577                 {\r
578                         count = ch&0xff;\r
579                         if (!count)\r
580                         {                               // have to insert a word containing the tag byte\r
581                                 ch |= *((unsigned char far *)inptr)++;\r
582                                 *outptr++ = ch;\r
583                                 length--;\r
584                         }\r
585                         else\r
586                         {\r
587                                 offset = *((unsigned char far *)inptr)++;\r
588                                 copyptr = outptr - offset;\r
589                                 length -= count;\r
590                                 while (count--)\r
591                                         *outptr++ = *copyptr++;\r
592                         }\r
593                 }\r
594                 else if (chhigh == FARTAG)\r
595                 {\r
596                         count = ch&0xff;\r
597                         if (!count)\r
598                         {                               // have to insert a word containing the tag byte\r
599                                 ch |= *((unsigned char far *)inptr)++;\r
600                                 *outptr++ = ch;\r
601                                 length --;\r
602                         }\r
603                         else\r
604                         {\r
605                                 offset = *inptr++;\r
606                                 copyptr = dest + offset;\r
607                                 length -= count;\r
608                                 while (count--)\r
609                                         *outptr++ = *copyptr++;\r
610                         }\r
611                 }\r
612                 else\r
613                 {\r
614                         *outptr++ = ch;\r
615                         length --;\r
616                 }\r
617         }\r
618 }\r
619 \r
620 \r
621 \r
622 /*\r
623 ======================\r
624 =\r
625 = CA_RLEWcompress\r
626 =\r
627 ======================\r
628 */\r
629 \r
630 long CA_RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,\r
631   unsigned rlewtag)\r
632 {\r
633   long complength;\r
634   unsigned value,count,i;\r
635   unsigned huge *start,huge *end;\r
636 \r
637   start = dest;\r
638 \r
639   end = source + (length+1)/2;\r
640 \r
641 //\r
642 // compress it\r
643 //\r
644   do\r
645   {\r
646         count = 1;\r
647         value = *source++;\r
648         while (*source == value && source<end)\r
649         {\r
650           count++;\r
651           source++;\r
652         }\r
653         if (count>3 || value == rlewtag)\r
654         {\r
655     //\r
656     // send a tag / count / value string\r
657     //\r
658       *dest++ = rlewtag;\r
659       *dest++ = count;\r
660       *dest++ = value;\r
661     }\r
662     else\r
663     {\r
664     //\r
665     // send word without compressing\r
666     //\r
667       for (i=1;i<=count;i++)\r
668         *dest++ = value;\r
669         }\r
670 \r
671   } while (source<end);\r
672 \r
673   complength = 2*(dest-start);\r
674   return complength;\r
675 }\r
676 \r
677 \r
678 /*\r
679 ======================\r
680 =\r
681 = CA_RLEWexpand\r
682 = length is EXPANDED length\r
683 =\r
684 ======================\r
685 */\r
686 \r
687 void CA_RLEWexpand (unsigned huge *source, unsigned huge *dest,long length,\r
688   unsigned rlewtag)\r
689 {\r
690 //  unsigned value,count,i;\r
691   unsigned huge *end;\r
692   unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;\r
693 \r
694 \r
695 //\r
696 // expand it\r
697 //\r
698 #if 0\r
699   do\r
700   {\r
701         value = *source++;\r
702         if (value != rlewtag)\r
703         //\r
704         // uncompressed\r
705         //\r
706           *dest++=value;\r
707         else\r
708         {\r
709         //\r
710         // compressed string\r
711         //\r
712           count = *source++;\r
713           value = *source++;\r
714           for (i=1;i<=count;i++)\r
715         *dest++ = value;\r
716         }\r
717   } while (dest<end);\r
718 #endif\r
719 \r
720   end = dest + (length)/2;\r
721   sourceseg = FP_SEG(source);\r
722   sourceoff = FP_OFF(source);\r
723   destseg = FP_SEG(dest);\r
724   destoff = FP_OFF(dest);\r
725   endseg = FP_SEG(end);\r
726   endoff = FP_OFF(end);\r
727 \r
728 \r
729 //\r
730 // ax = source value\r
731 // bx = tag value\r
732 // cx = repeat counts\r
733 // dx = scratch\r
734 //\r
735 // NOTE: A repeat count that produces 0xfff0 bytes can blow this!\r
736 //\r
737 \r
738 asm     mov     bx,rlewtag\r
739 asm     mov     si,sourceoff\r
740 asm     mov     di,destoff\r
741 asm     mov     es,destseg\r
742 asm     mov     ds,sourceseg\r
743 \r
744 expand:\r
745 asm     lodsw\r
746 asm     cmp     ax,bx\r
747 asm     je      repeat\r
748 asm     stosw\r
749 asm     jmp     next\r
750 \r
751 repeat:\r
752 asm     lodsw\r
753 asm     mov     cx,ax           // repeat count\r
754 asm     lodsw                   // repeat value\r
755 asm     rep stosw\r
756 \r
757 next:\r
758 \r
759 asm     cmp     si,0x10         // normalize ds:si\r
760 asm     jb      sinorm\r
761 asm     mov     ax,si\r
762 asm     shr     ax,1\r
763 asm     shr     ax,1\r
764 asm     shr     ax,1\r
765 asm     shr     ax,1\r
766 asm     mov     dx,ds\r
767 asm     add     dx,ax\r
768 asm     mov     ds,dx\r
769 asm     and     si,0xf\r
770 sinorm:\r
771 asm     cmp     di,0x10         // normalize es:di\r
772 asm     jb      dinorm\r
773 asm     mov     ax,di\r
774 asm     shr     ax,1\r
775 asm     shr     ax,1\r
776 asm     shr     ax,1\r
777 asm     shr     ax,1\r
778 asm     mov     dx,es\r
779 asm     add     dx,ax\r
780 asm     mov     es,dx\r
781 asm     and     di,0xf\r
782 dinorm:\r
783 \r
784 asm     cmp     di,ss:endoff\r
785 asm     jne     expand\r
786 asm     mov     ax,es\r
787 asm     cmp     ax,ss:endseg\r
788 asm     jb      expand\r
789 \r
790 asm     mov     ax,ss\r
791 asm     mov     ds,ax\r
792 \r
793 }\r
794 \r
795 \r
796 \r
797 /*\r
798 =============================================================================\r
799 \r
800                                          CACHE MANAGER ROUTINES\r
801 \r
802 =============================================================================\r
803 */\r
804 \r
805 \r
806 /*\r
807 ======================\r
808 =\r
809 = CAL_SetupGrFile\r
810 =\r
811 ======================\r
812 */\r
813 \r
814 void CAL_SetupGrFile (void)\r
815 {\r
816         int handle;\r
817         memptr compseg;\r
818 \r
819 #ifdef GRHEADERLINKED\r
820 \r
821 #if GRMODE == EGAGR\r
822         grhuffman = (huffnode *)&EGAdict;\r
823         grstarts = (long _seg *)FP_SEG(&EGAhead);\r
824 #endif\r
825 #if GRMODE == CGAGR\r
826         grhuffman = (huffnode *)&CGAdict;\r
827         grstarts = (long _seg *)FP_SEG(&CGAhead);\r
828 #endif\r
829 \r
830         CAL_OptimizeNodes (grhuffman);\r
831 \r
832 #else\r
833 \r
834 //\r
835 // load ???dict.ext (huffman dictionary for graphics files)\r
836 //\r
837 \r
838         if ((handle = open(GREXT"DICT."EXTENSION,\r
839                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
840                 Quit ("Can't open "GREXT"DICT."EXTENSION"!");\r
841 \r
842         read(handle, &grhuffman, sizeof(grhuffman));\r
843         close(handle);\r
844         CAL_OptimizeNodes (grhuffman);\r
845 //\r
846 // load the data offsets from ???head.ext\r
847 //\r
848         MM_GetPtr (&(memptr)grstarts,(NUMCHUNKS+1)*FILEPOSSIZE);\r
849 \r
850         if ((handle = open(GREXT"HEAD."EXTENSION,\r
851                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
852                 Quit ("Can't open "GREXT"HEAD."EXTENSION"!");\r
853 \r
854         CA_FarRead(handle, (memptr)grstarts, (NUMCHUNKS+1)*FILEPOSSIZE);\r
855 \r
856         close(handle);\r
857 \r
858 \r
859 #endif\r
860 \r
861 //\r
862 // Open the graphics file, leaving it open until the game is finished\r
863 //\r
864         grhandle = open(GREXT"GRAPH."EXTENSION, O_RDONLY | O_BINARY);\r
865         if (grhandle == -1)\r
866                 Quit ("Cannot open "GREXT"GRAPH."EXTENSION"!");\r
867 \r
868 \r
869 //\r
870 // load the pic and sprite headers into the arrays in the data segment\r
871 //\r
872 #if NUMPICS>0\r
873         MM_GetPtr(&(memptr)pictable,NUMPICS*sizeof(pictabletype));\r
874         CAL_GetGrChunkLength(STRUCTPIC);                // position file pointer\r
875         MM_GetPtr(&compseg,chunkcomplen);\r
876         CA_FarRead (grhandle,compseg,chunkcomplen);\r
877         CAL_HuffExpand (compseg, (byte huge *)pictable,NUMPICS*sizeof(pictabletype),grhuffman);\r
878         MM_FreePtr(&compseg);\r
879 #endif\r
880 \r
881 #if NUMPICM>0\r
882         MM_GetPtr(&(memptr)picmtable,NUMPICM*sizeof(pictabletype));\r
883         CAL_GetGrChunkLength(STRUCTPICM);               // position file pointer\r
884         MM_GetPtr(&compseg,chunkcomplen);\r
885         CA_FarRead (grhandle,compseg,chunkcomplen);\r
886         CAL_HuffExpand (compseg, (byte huge *)picmtable,NUMPICS*sizeof(pictabletype),grhuffman);\r
887         MM_FreePtr(&compseg);\r
888 #endif\r
889 \r
890 #if NUMSPRITES>0\r
891         MM_GetPtr(&(memptr)spritetable,NUMSPRITES*sizeof(spritetabletype));\r
892         CAL_GetGrChunkLength(STRUCTSPRITE);     // position file pointer\r
893         MM_GetPtr(&compseg,chunkcomplen);\r
894         CA_FarRead (grhandle,compseg,chunkcomplen);\r
895         CAL_HuffExpand (compseg, (byte huge *)spritetable,NUMSPRITES*sizeof(spritetabletype),grhuffman);\r
896         MM_FreePtr(&compseg);\r
897 #endif\r
898 \r
899 }\r
900 \r
901 //==========================================================================\r
902 \r
903 \r
904 /*\r
905 ======================\r
906 =\r
907 = CAL_SetupMapFile\r
908 =\r
909 ======================\r
910 */\r
911 \r
912 void CAL_SetupMapFile (void)\r
913 {\r
914         int handle;\r
915         long length;\r
916 \r
917 //\r
918 // load maphead.ext (offsets and tileinfo for map file)\r
919 //\r
920 #ifndef MAPHEADERLINKED\r
921         if ((handle = open("MAPHEAD."EXTENSION,\r
922                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
923                 Quit ("Can't open MAPHEAD."EXTENSION"!");\r
924         length = filelength(handle);\r
925         MM_GetPtr (&(memptr)tinf,length);\r
926         CA_FarRead(handle, tinf, length);\r
927         close(handle);\r
928 #else\r
929 \r
930         tinf = (byte _seg *)FP_SEG(&maphead);\r
931 \r
932 #endif\r
933 \r
934 //\r
935 // open the data file\r
936 //\r
937 #ifdef MAPHEADERLINKED\r
938         if ((maphandle = open("GAMEMAPS."EXTENSION,\r
939                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
940                 Quit ("Can't open GAMEMAPS."EXTENSION"!");\r
941 #else\r
942         if ((maphandle = open("MAPTEMP."EXTENSION,\r
943                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
944                 Quit ("Can't open MAPTEMP."EXTENSION"!");\r
945 #endif\r
946 }\r
947 \r
948 //==========================================================================\r
949 \r
950 \r
951 /*\r
952 ======================\r
953 =\r
954 = CAL_SetupAudioFile\r
955 =\r
956 ======================\r
957 */\r
958 \r
959 void CAL_SetupAudioFile (void)\r
960 {\r
961         int handle;\r
962         long length;\r
963 \r
964 //\r
965 // load maphead.ext (offsets and tileinfo for map file)\r
966 //\r
967 #ifndef AUDIOHEADERLINKED\r
968         if ((handle = open("AUDIOHED."EXTENSION,\r
969                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
970                 Quit ("Can't open AUDIOHED."EXTENSION"!");\r
971         length = filelength(handle);\r
972         MM_GetPtr (&(memptr)audiostarts,length);\r
973         CA_FarRead(handle, (byte far *)audiostarts, length);\r
974         close(handle);\r
975 #else\r
976         audiohuffman = (huffnode *)&audiodict;\r
977         CAL_OptimizeNodes (audiohuffman);\r
978         audiostarts = (long _seg *)FP_SEG(&audiohead);\r
979 #endif\r
980 \r
981 //\r
982 // open the data file\r
983 //\r
984 #ifndef AUDIOHEADERLINKED\r
985         if ((audiohandle = open("AUDIOT."EXTENSION,\r
986                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
987                 Quit ("Can't open AUDIOT."EXTENSION"!");\r
988 #else\r
989         if ((audiohandle = open("AUDIO."EXTENSION,\r
990                  O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
991                 Quit ("Can't open AUDIO."EXTENSION"!");\r
992 #endif\r
993 }\r
994 \r
995 //==========================================================================\r
996 \r
997 \r
998 /*\r
999 ======================\r
1000 =\r
1001 = CA_Startup\r
1002 =\r
1003 = Open all files and load in headers\r
1004 =\r
1005 ======================\r
1006 */\r
1007 \r
1008 void CA_Startup (void)\r
1009 {\r
1010 #ifdef PROFILE\r
1011         unlink ("PROFILE.TXT");\r
1012         profilehandle = open("PROFILE.TXT", O_CREAT | O_WRONLY | O_TEXT);\r
1013 #endif\r
1014 \r
1015 #ifndef NOMAPS\r
1016         CAL_SetupMapFile ();\r
1017 #endif\r
1018 #ifndef NOGRAPHICS\r
1019         CAL_SetupGrFile ();\r
1020 #endif\r
1021 #ifndef NOAUDIO\r
1022         CAL_SetupAudioFile ();\r
1023 #endif\r
1024 \r
1025         mapon = -1;\r
1026         ca_levelbit = 1;\r
1027         ca_levelnum = 0;\r
1028 \r
1029         drawcachebox    = CAL_DialogDraw;\r
1030         updatecachebox  = CAL_DialogUpdate;\r
1031         finishcachebox  = CAL_DialogFinish;\r
1032 }\r
1033 \r
1034 //==========================================================================\r
1035 \r
1036 \r
1037 /*\r
1038 ======================\r
1039 =\r
1040 = CA_Shutdown\r
1041 =\r
1042 = Closes all files\r
1043 =\r
1044 ======================\r
1045 */\r
1046 \r
1047 void CA_Shutdown (void)\r
1048 {\r
1049 #ifdef PROFILE\r
1050         close (profilehandle);\r
1051 #endif\r
1052 \r
1053         close (maphandle);\r
1054         close (grhandle);\r
1055         close (audiohandle);\r
1056 }\r
1057 \r
1058 //===========================================================================\r
1059 \r
1060 /*\r
1061 ======================\r
1062 =\r
1063 = CA_CacheAudioChunk\r
1064 =\r
1065 ======================\r
1066 */\r
1067 \r
1068 void CA_CacheAudioChunk (int chunk)\r
1069 {\r
1070         long    pos,compressed;\r
1071 #ifdef AUDIOHEADERLINKED\r
1072         long    expanded;\r
1073         memptr  bigbufferseg;\r
1074         byte    far *source;\r
1075 #endif\r
1076 \r
1077         if (audiosegs[chunk])\r
1078         {\r
1079                 MM_SetPurge (&(memptr)audiosegs[chunk],0);\r
1080                 return;                                                 // allready in memory\r
1081         }\r
1082 \r
1083 //\r
1084 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
1085 // a larger buffer\r
1086 //\r
1087         pos = audiostarts[chunk];\r
1088         compressed = audiostarts[chunk+1]-pos;\r
1089 \r
1090         lseek(audiohandle,pos,SEEK_SET);\r
1091 \r
1092 #ifndef AUDIOHEADERLINKED\r
1093 \r
1094         MM_GetPtr (&(memptr)audiosegs[chunk],compressed);\r
1095         if (mmerror)\r
1096                 return;\r
1097 \r
1098         CA_FarRead(audiohandle,audiosegs[chunk],compressed);\r
1099 \r
1100 #else\r
1101 \r
1102         if (compressed<=BUFFERSIZE)\r
1103         {\r
1104                 CA_FarRead(audiohandle,bufferseg,compressed);\r
1105                 source = bufferseg;\r
1106         }\r
1107         else\r
1108         {\r
1109                 MM_GetPtr(&bigbufferseg,compressed);\r
1110                 if (mmerror)\r
1111                         return;\r
1112                 MM_SetLock (&bigbufferseg,true);\r
1113                 CA_FarRead(audiohandle,bigbufferseg,compressed);\r
1114                 source = bigbufferseg;\r
1115         }\r
1116 \r
1117         expanded = *(long far *)source;\r
1118         source += 4;                    // skip over length\r
1119         MM_GetPtr (&(memptr)audiosegs[chunk],expanded);\r
1120         if (mmerror)\r
1121                 goto done;\r
1122         CAL_HuffExpand (source,audiosegs[chunk],expanded,audiohuffman);\r
1123 \r
1124 done:\r
1125         if (compressed>BUFFERSIZE)\r
1126                 MM_FreePtr(&bigbufferseg);\r
1127 #endif\r
1128 }\r
1129 \r
1130 //===========================================================================\r
1131 \r
1132 /*\r
1133 ======================\r
1134 =\r
1135 = CA_LoadAllSounds\r
1136 =\r
1137 = Purges all sounds, then loads all new ones (mode switch)\r
1138 =\r
1139 ======================\r
1140 */\r
1141 \r
1142 void CA_LoadAllSounds (void)\r
1143 {\r
1144         unsigned        start,i;\r
1145 \r
1146         switch (oldsoundmode)\r
1147         {\r
1148         case sdm_Off:\r
1149                 goto cachein;\r
1150         case sdm_PC:\r
1151                 start = STARTPCSOUNDS;\r
1152                 break;\r
1153         case sdm_AdLib:\r
1154                 start = STARTADLIBSOUNDS;\r
1155                 break;\r
1156         }\r
1157 \r
1158         for (i=0;i<NUMSOUNDS;i++,start++)\r
1159                 if (audiosegs[start])\r
1160                         MM_SetPurge (&(memptr)audiosegs[start],3);              // make purgable\r
1161 \r
1162 cachein:\r
1163 \r
1164         switch (SoundMode)\r
1165         {\r
1166         case sdm_Off:\r
1167                 return;\r
1168         case sdm_PC:\r
1169                 start = STARTPCSOUNDS;\r
1170                 break;\r
1171         case sdm_AdLib:\r
1172                 start = STARTADLIBSOUNDS;\r
1173                 break;\r
1174         }\r
1175 \r
1176         for (i=0;i<NUMSOUNDS;i++,start++)\r
1177                 CA_CacheAudioChunk (start);\r
1178 \r
1179         oldsoundmode = SoundMode;\r
1180 }\r
1181 \r
1182 //===========================================================================\r
1183 \r
1184 #if GRMODE == EGAGR\r
1185 \r
1186 /*\r
1187 ======================\r
1188 =\r
1189 = CAL_ShiftSprite\r
1190 =\r
1191 = Make a shifted (one byte wider) copy of a sprite into another area\r
1192 =\r
1193 ======================\r
1194 */\r
1195 \r
1196 unsigned        static  sheight,swidth;\r
1197 \r
1198 void CAL_ShiftSprite (unsigned segment,unsigned source,unsigned dest,\r
1199         unsigned width, unsigned height, unsigned pixshift)\r
1200 {\r
1201 \r
1202         sheight = height;               // because we are going to reassign bp\r
1203         swidth = width;\r
1204 \r
1205 asm     mov     ax,[segment]\r
1206 asm     mov     ds,ax           // source and dest are in same segment, and all local\r
1207 \r
1208 asm     mov     bx,[source]\r
1209 asm     mov     di,[dest]\r
1210 \r
1211 asm     mov     bp,[pixshift]\r
1212 asm     shl     bp,1\r
1213 asm     mov     bp,WORD PTR [shifttabletable+bp]        // bp holds pointer to shift table\r
1214 \r
1215 //\r
1216 // table shift the mask\r
1217 //\r
1218 asm     mov     dx,[ss:sheight]\r
1219 \r
1220 domaskrow:\r
1221 \r
1222 asm     mov     BYTE PTR [di],255       // 0xff first byte\r
1223 asm     mov     cx,ss:[swidth]\r
1224 \r
1225 domaskbyte:\r
1226 \r
1227 asm     mov     al,[bx]                         // source\r
1228 asm     not     al\r
1229 asm     inc     bx                                      // next source byte\r
1230 asm     xor     ah,ah\r
1231 asm     shl     ax,1\r
1232 asm     mov     si,ax\r
1233 asm     mov     ax,[bp+si]                      // table shift into two bytes\r
1234 asm     not     ax\r
1235 asm     and     [di],al                         // and with first byte\r
1236 asm     inc     di\r
1237 asm     mov     [di],ah                         // replace next byte\r
1238 \r
1239 asm     loop    domaskbyte\r
1240 \r
1241 asm     inc     di                                      // the last shifted byte has 1s in it\r
1242 asm     dec     dx\r
1243 asm     jnz     domaskrow\r
1244 \r
1245 //\r
1246 // table shift the data\r
1247 //\r
1248 asm     mov     dx,ss:[sheight]\r
1249 asm     shl     dx,1\r
1250 asm     shl     dx,1                            // four planes of data\r
1251 \r
1252 dodatarow:\r
1253 \r
1254 asm     mov     BYTE PTR [di],0         // 0 first byte\r
1255 asm     mov     cx,ss:[swidth]\r
1256 \r
1257 dodatabyte:\r
1258 \r
1259 asm     mov     al,[bx]                         // source\r
1260 asm     inc     bx                                      // next source byte\r
1261 asm     xor     ah,ah\r
1262 asm     shl     ax,1\r
1263 asm     mov     si,ax\r
1264 asm     mov     ax,[bp+si]                      // table shift into two bytes\r
1265 asm     or      [di],al                         // or with first byte\r
1266 asm     inc     di\r
1267 asm     mov     [di],ah                         // replace next byte\r
1268 \r
1269 asm     loop    dodatabyte\r
1270 \r
1271 asm     inc     di                                      // the last shifted byte has 0s in it\r
1272 asm     dec     dx\r
1273 asm     jnz     dodatarow\r
1274 \r
1275 //\r
1276 // done\r
1277 //\r
1278 \r
1279 asm     mov     ax,ss                           // restore data segment\r
1280 asm     mov     ds,ax\r
1281 \r
1282 }\r
1283 \r
1284 #endif\r
1285 \r
1286 //===========================================================================\r
1287 \r
1288 /*\r
1289 ======================\r
1290 =\r
1291 = CAL_CacheSprite\r
1292 =\r
1293 = Generate shifts and set up sprite structure for a given sprite\r
1294 =\r
1295 ======================\r
1296 */\r
1297 \r
1298 void CAL_CacheSprite (int chunk, byte far *compressed)\r
1299 {\r
1300         int i;\r
1301         unsigned shiftstarts[5];\r
1302         unsigned smallplane,bigplane,expanded;\r
1303         spritetabletype far *spr;\r
1304         spritetype _seg *dest;\r
1305 \r
1306 #if GRMODE == CGAGR\r
1307 //\r
1308 // CGA has no pel panning, so shifts are never needed\r
1309 //\r
1310         spr = &spritetable[chunk-STARTSPRITES];\r
1311         smallplane = spr->width*spr->height;\r
1312         MM_GetPtr (&grsegs[chunk],smallplane*2+MAXSHIFTS*6);\r
1313         if (mmerror)\r
1314                 return;\r
1315         dest = (spritetype _seg *)grsegs[chunk];\r
1316         dest->sourceoffset[0] = MAXSHIFTS*6;    // start data after 3 unsigned tables\r
1317         dest->planesize[0] = smallplane;\r
1318         dest->width[0] = spr->width;\r
1319 \r
1320 //\r
1321 // expand the unshifted shape\r
1322 //\r
1323         CAL_HuffExpand (compressed, &dest->data[0],smallplane*2,grhuffman);\r
1324 \r
1325 #endif\r
1326 \r
1327 \r
1328 #if GRMODE == EGAGR\r
1329 \r
1330 //\r
1331 // calculate sizes\r
1332 //\r
1333         spr = &spritetable[chunk-STARTSPRITES];\r
1334         smallplane = spr->width*spr->height;\r
1335         bigplane = (spr->width+1)*spr->height;\r
1336 \r
1337         shiftstarts[0] = MAXSHIFTS*6;   // start data after 3 unsigned tables\r
1338         shiftstarts[1] = shiftstarts[0] + smallplane*5; // 5 planes in a sprite\r
1339         shiftstarts[2] = shiftstarts[1] + bigplane*5;\r
1340         shiftstarts[3] = shiftstarts[2] + bigplane*5;\r
1341         shiftstarts[4] = shiftstarts[3] + bigplane*5;   // nothing ever put here\r
1342 \r
1343         expanded = shiftstarts[spr->shifts];\r
1344         MM_GetPtr (&grsegs[chunk],expanded);\r
1345         if (mmerror)\r
1346                 return;\r
1347         dest = (spritetype _seg *)grsegs[chunk];\r
1348 \r
1349 //\r
1350 // expand the unshifted shape\r
1351 //\r
1352         CAL_HuffExpand (compressed, &dest->data[0],smallplane*5,grhuffman);\r
1353 \r
1354 //\r
1355 // make the shifts!\r
1356 //\r
1357         switch (spr->shifts)\r
1358         {\r
1359         case    1:\r
1360                 for (i=0;i<4;i++)\r
1361                 {\r
1362                         dest->sourceoffset[i] = shiftstarts[0];\r
1363                         dest->planesize[i] = smallplane;\r
1364                         dest->width[i] = spr->width;\r
1365                 }\r
1366                 break;\r
1367 \r
1368         case    2:\r
1369                 for (i=0;i<2;i++)\r
1370                 {\r
1371                         dest->sourceoffset[i] = shiftstarts[0];\r
1372                         dest->planesize[i] = smallplane;\r
1373                         dest->width[i] = spr->width;\r
1374                 }\r
1375                 for (i=2;i<4;i++)\r
1376                 {\r
1377                         dest->sourceoffset[i] = shiftstarts[1];\r
1378                         dest->planesize[i] = bigplane;\r
1379                         dest->width[i] = spr->width+1;\r
1380                 }\r
1381                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1382                         dest->sourceoffset[2],spr->width,spr->height,4);\r
1383                 break;\r
1384 \r
1385         case    4:\r
1386                 dest->sourceoffset[0] = shiftstarts[0];\r
1387                 dest->planesize[0] = smallplane;\r
1388                 dest->width[0] = spr->width;\r
1389 \r
1390                 dest->sourceoffset[1] = shiftstarts[1];\r
1391                 dest->planesize[1] = bigplane;\r
1392                 dest->width[1] = spr->width+1;\r
1393                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1394                         dest->sourceoffset[1],spr->width,spr->height,2);\r
1395 \r
1396                 dest->sourceoffset[2] = shiftstarts[2];\r
1397                 dest->planesize[2] = bigplane;\r
1398                 dest->width[2] = spr->width+1;\r
1399                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1400                         dest->sourceoffset[2],spr->width,spr->height,4);\r
1401 \r
1402                 dest->sourceoffset[3] = shiftstarts[3];\r
1403                 dest->planesize[3] = bigplane;\r
1404                 dest->width[3] = spr->width+1;\r
1405                 CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0],\r
1406                         dest->sourceoffset[3],spr->width,spr->height,6);\r
1407 \r
1408                 break;\r
1409 \r
1410         default:\r
1411                 Quit ("CAL_CacheSprite: Bad shifts number!");\r
1412         }\r
1413 \r
1414 #endif\r
1415 }\r
1416 \r
1417 //===========================================================================\r
1418 \r
1419 \r
1420 /*\r
1421 ======================\r
1422 =\r
1423 = CAL_ExpandGrChunk\r
1424 =\r
1425 = Does whatever is needed with a pointer to a compressed chunk\r
1426 =\r
1427 ======================\r
1428 */\r
1429 \r
1430 void CAL_ExpandGrChunk (int chunk, byte far *source)\r
1431 {\r
1432         long    expanded;\r
1433 \r
1434 \r
1435         if (chunk >= STARTTILE8 && chunk < STARTEXTERNS)\r
1436         {\r
1437         //\r
1438         // expanded sizes of tile8/16/32 are implicit\r
1439         //\r
1440 \r
1441 #if GRMODE == EGAGR\r
1442 #define BLOCK           32\r
1443 #define MASKBLOCK       40\r
1444 #endif\r
1445 \r
1446 #if GRMODE == CGAGR\r
1447 #define BLOCK           16\r
1448 #define MASKBLOCK       32\r
1449 #endif\r
1450 \r
1451                 if (chunk<STARTTILE8M)                  // tile 8s are all in one chunk!\r
1452                         expanded = BLOCK*NUMTILE8;\r
1453                 else if (chunk<STARTTILE16)\r
1454                         expanded = MASKBLOCK*NUMTILE8M;\r
1455                 else if (chunk<STARTTILE16M)    // all other tiles are one/chunk\r
1456                         expanded = BLOCK*4;\r
1457                 else if (chunk<STARTTILE32)\r
1458                         expanded = MASKBLOCK*4;\r
1459                 else if (chunk<STARTTILE32M)\r
1460                         expanded = BLOCK*16;\r
1461                 else\r
1462                         expanded = MASKBLOCK*16;\r
1463         }\r
1464         else\r
1465         {\r
1466         //\r
1467         // everything else has an explicit size longword\r
1468         //\r
1469                 expanded = *(long far *)source;\r
1470                 source += 4;                    // skip over length\r
1471         }\r
1472 \r
1473 //\r
1474 // allocate final space, decompress it, and free bigbuffer\r
1475 // Sprites need to have shifts made and various other junk\r
1476 //\r
1477         if (chunk>=STARTSPRITES && chunk< STARTTILE8)\r
1478                 CAL_CacheSprite(chunk,source);\r
1479         else\r
1480         {\r
1481                 MM_GetPtr (&grsegs[chunk],expanded);\r
1482                 if (mmerror)\r
1483                         return;\r
1484                 CAL_HuffExpand (source,grsegs[chunk],expanded,grhuffman);\r
1485         }\r
1486 }\r
1487 \r
1488 \r
1489 /*\r
1490 ======================\r
1491 =\r
1492 = CAL_ReadGrChunk\r
1493 =\r
1494 = Gets a chunk off disk, optimizing reads to general buffer\r
1495 =\r
1496 ======================\r
1497 */\r
1498 \r
1499 void CAL_ReadGrChunk (int chunk)\r
1500 {\r
1501         long    pos,compressed;\r
1502         memptr  bigbufferseg;\r
1503         byte    far *source;\r
1504         int             next;\r
1505 \r
1506 //\r
1507 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
1508 // a larger buffer\r
1509 //\r
1510         pos = GRFILEPOS(chunk);\r
1511         if (pos<0)                                                      // $FFFFFFFF start is a sparse tile\r
1512           return;\r
1513 \r
1514         next = chunk +1;\r
1515         while (GRFILEPOS(next) == -1)           // skip past any sparse tiles\r
1516                 next++;\r
1517 \r
1518         compressed = GRFILEPOS(next)-pos;\r
1519 \r
1520         lseek(grhandle,pos,SEEK_SET);\r
1521 \r
1522         if (compressed<=BUFFERSIZE)\r
1523         {\r
1524                 CA_FarRead(grhandle,bufferseg,compressed);\r
1525                 source = bufferseg;\r
1526         }\r
1527         else\r
1528         {\r
1529                 MM_GetPtr(&bigbufferseg,compressed);\r
1530                 if (mmerror)\r
1531                         return;\r
1532                 MM_SetLock (&bigbufferseg,true);\r
1533                 CA_FarRead(grhandle,bigbufferseg,compressed);\r
1534                 source = bigbufferseg;\r
1535         }\r
1536 \r
1537         CAL_ExpandGrChunk (chunk,source);\r
1538 \r
1539         if (compressed>BUFFERSIZE)\r
1540                 MM_FreePtr(&bigbufferseg);\r
1541 }\r
1542 \r
1543 \r
1544 /*\r
1545 ======================\r
1546 =\r
1547 = CA_CacheGrChunk\r
1548 =\r
1549 = Makes sure a given chunk is in memory, loadiing it if needed\r
1550 =\r
1551 ======================\r
1552 */\r
1553 \r
1554 void CA_CacheGrChunk (int chunk)\r
1555 {\r
1556         long    pos,compressed;\r
1557         memptr  bigbufferseg;\r
1558         byte    far *source;\r
1559         int             next;\r
1560 \r
1561         grneeded[chunk] |= ca_levelbit;         // make sure it doesn't get removed\r
1562         if (grsegs[chunk])\r
1563         {\r
1564                 MM_SetPurge (&grsegs[chunk],0);\r
1565                 return;                                                 // allready in memory\r
1566         }\r
1567 \r
1568 //\r
1569 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
1570 // a larger buffer\r
1571 //\r
1572         pos = GRFILEPOS(chunk);\r
1573         if (pos<0)                                                      // $FFFFFFFF start is a sparse tile\r
1574           return;\r
1575 \r
1576         next = chunk +1;\r
1577         while (GRFILEPOS(next) == -1)           // skip past any sparse tiles\r
1578                 next++;\r
1579 \r
1580         compressed = GRFILEPOS(next)-pos;\r
1581 \r
1582         lseek(grhandle,pos,SEEK_SET);\r
1583 \r
1584         if (compressed<=BUFFERSIZE)\r
1585         {\r
1586                 CA_FarRead(grhandle,bufferseg,compressed);\r
1587                 source = bufferseg;\r
1588         }\r
1589         else\r
1590         {\r
1591                 MM_GetPtr(&bigbufferseg,compressed);\r
1592                 MM_SetLock (&bigbufferseg,true);\r
1593                 CA_FarRead(grhandle,bigbufferseg,compressed);\r
1594                 source = bigbufferseg;\r
1595         }\r
1596 \r
1597         CAL_ExpandGrChunk (chunk,source);\r
1598 \r
1599         if (compressed>BUFFERSIZE)\r
1600                 MM_FreePtr(&bigbufferseg);\r
1601 }\r
1602 \r
1603 \r
1604 \r
1605 //==========================================================================\r
1606 \r
1607 /*\r
1608 ======================\r
1609 =\r
1610 = CA_CacheMap\r
1611 =\r
1612 ======================\r
1613 */\r
1614 \r
1615 void CA_CacheMap (int mapnum)\r
1616 {\r
1617         long    pos,compressed;\r
1618         int             plane;\r
1619         memptr  *dest,bigbufferseg;\r
1620         unsigned        size;\r
1621         unsigned        far     *source;\r
1622 #ifdef MAPHEADERLINKED\r
1623         memptr  buffer2seg;\r
1624         long    expanded;\r
1625 #endif\r
1626 \r
1627 \r
1628 //\r
1629 // free up memory from last map\r
1630 //\r
1631         if (mapon>-1 && mapheaderseg[mapon])\r
1632                 MM_SetPurge (&(memptr)mapheaderseg[mapon],3);\r
1633         for (plane=0;plane<MAPPLANES;plane++)\r
1634                 if (mapsegs[plane])\r
1635                         MM_FreePtr (&(memptr)mapsegs[plane]);\r
1636 \r
1637         mapon = mapnum;\r
1638 \r
1639 \r
1640 //\r
1641 // load map header\r
1642 // The header will be cached if it is still around\r
1643 //\r
1644         if (!mapheaderseg[mapnum])\r
1645         {\r
1646                 pos = ((mapfiletype     _seg *)tinf)->headeroffsets[mapnum];\r
1647                 if (pos<0)                                              // $FFFFFFFF start is a sparse map\r
1648                   Quit ("CA_CacheMap: Tried to load a non existent map!");\r
1649 \r
1650                 MM_GetPtr(&(memptr)mapheaderseg[mapnum],sizeof(maptype));\r
1651                 lseek(maphandle,pos,SEEK_SET);\r
1652                 CA_FarRead (maphandle,(memptr)mapheaderseg[mapnum],sizeof(maptype));\r
1653         }\r
1654         else\r
1655                 MM_SetPurge (&(memptr)mapheaderseg[mapnum],0);\r
1656 \r
1657 //\r
1658 // load the planes in\r
1659 // If a plane's pointer still exists it will be overwritten (levels are\r
1660 // allways reloaded, never cached)\r
1661 //\r
1662 \r
1663         size = mapheaderseg[mapnum]->width * mapheaderseg[mapnum]->height * 2;\r
1664 \r
1665         for (plane = 0; plane<MAPPLANES; plane++)\r
1666         {\r
1667                 pos = mapheaderseg[mapnum]->planestart[plane];\r
1668                 compressed = mapheaderseg[mapnum]->planelength[plane];\r
1669 \r
1670                 if (!compressed)\r
1671                         continue;               // the plane is not used in this game\r
1672 \r
1673                 dest = &(memptr)mapsegs[plane];\r
1674                 MM_GetPtr(dest,size);\r
1675 \r
1676                 lseek(maphandle,pos,SEEK_SET);\r
1677                 if (compressed<=BUFFERSIZE)\r
1678                         source = bufferseg;\r
1679                 else\r
1680                 {\r
1681                         MM_GetPtr(&bigbufferseg,compressed);\r
1682                         MM_SetLock (&bigbufferseg,true);\r
1683                         source = bigbufferseg;\r
1684                 }\r
1685 \r
1686                 CA_FarRead(maphandle,(byte far *)source,compressed);\r
1687 #ifdef MAPHEADERLINKED\r
1688                 //\r
1689                 // unhuffman, then unRLEW\r
1690                 // The huffman'd chunk has a two byte expanded length first\r
1691                 // The resulting RLEW chunk also does, even though it's not really\r
1692                 // needed\r
1693                 //\r
1694                 expanded = *source;\r
1695                 source++;\r
1696                 MM_GetPtr (&buffer2seg,expanded);\r
1697                 CAL_CarmackExpand (source, (unsigned far *)buffer2seg,expanded);\r
1698                 CA_RLEWexpand (((unsigned far *)buffer2seg)+1,*dest,size,\r
1699                 ((mapfiletype _seg *)tinf)->RLEWtag);\r
1700                 MM_FreePtr (&buffer2seg);\r
1701 \r
1702 #else\r
1703                 //\r
1704                 // unRLEW, skipping expanded length\r
1705                 //\r
1706                 CA_RLEWexpand (source+1, *dest,size,\r
1707                 ((mapfiletype _seg *)tinf)->RLEWtag);\r
1708 #endif\r
1709 \r
1710                 if (compressed>BUFFERSIZE)\r
1711                         MM_FreePtr(&bigbufferseg);\r
1712         }\r
1713 }\r
1714 \r
1715 //===========================================================================\r
1716 \r
1717 /*\r
1718 ======================\r
1719 =\r
1720 = CA_UpLevel\r
1721 =\r
1722 = Goes up a bit level in the needed lists and clears it out.\r
1723 = Everything is made purgable\r
1724 =\r
1725 ======================\r
1726 */\r
1727 \r
1728 void CA_UpLevel (void)\r
1729 {\r
1730         if (ca_levelnum==7)\r
1731                 Quit ("CA_UpLevel: Up past level 7!");\r
1732 \r
1733         ca_levelbit<<=1;\r
1734         ca_levelnum++;\r
1735 }\r
1736 \r
1737 //===========================================================================\r
1738 \r
1739 /*\r
1740 ======================\r
1741 =\r
1742 = CA_DownLevel\r
1743 =\r
1744 = Goes down a bit level in the needed lists and recaches\r
1745 = everything from the lower level\r
1746 =\r
1747 ======================\r
1748 */\r
1749 \r
1750 void CA_DownLevel (void)\r
1751 {\r
1752         if (!ca_levelnum)\r
1753                 Quit ("CA_DownLevel: Down past level 0!");\r
1754         ca_levelbit>>=1;\r
1755         ca_levelnum--;\r
1756         CA_CacheMarks(NULL);\r
1757 }\r
1758 \r
1759 //===========================================================================\r
1760 \r
1761 /*\r
1762 ======================\r
1763 =\r
1764 = CA_ClearMarks\r
1765 =\r
1766 = Clears out all the marks at the current level\r
1767 =\r
1768 ======================\r
1769 */\r
1770 \r
1771 void CA_ClearMarks (void)\r
1772 {\r
1773         int i;\r
1774 \r
1775         for (i=0;i<NUMCHUNKS;i++)\r
1776                 grneeded[i]&=~ca_levelbit;\r
1777 }\r
1778 \r
1779 \r
1780 //===========================================================================\r
1781 \r
1782 /*\r
1783 ======================\r
1784 =\r
1785 = CA_ClearAllMarks\r
1786 =\r
1787 = Clears out all the marks on all the levels\r
1788 =\r
1789 ======================\r
1790 */\r
1791 \r
1792 void CA_ClearAllMarks (void)\r
1793 {\r
1794         _fmemset (grneeded,0,sizeof(grneeded));\r
1795         ca_levelbit = 1;\r
1796         ca_levelnum = 0;\r
1797 }\r
1798 \r
1799 \r
1800 //===========================================================================\r
1801 \r
1802 /*\r
1803 ======================\r
1804 =\r
1805 = CA_FreeGraphics\r
1806 =\r
1807 ======================\r
1808 */\r
1809 \r
1810 void CA_FreeGraphics (void)\r
1811 {\r
1812         int     i;\r
1813 \r
1814         for (i=0;i<NUMCHUNKS;i++)\r
1815                 if (grsegs[i])\r
1816                         MM_SetPurge (&(memptr)grsegs[i],3);\r
1817 }\r
1818 \r
1819 \r
1820 /*\r
1821 ======================\r
1822 =\r
1823 = CA_SetAllPurge\r
1824 =\r
1825 = Make everything possible purgable\r
1826 =\r
1827 ======================\r
1828 */\r
1829 \r
1830 void CA_SetAllPurge (void)\r
1831 {\r
1832         int i;\r
1833 \r
1834         CA_ClearMarks ();\r
1835 \r
1836 //\r
1837 // free cursor sprite and background save\r
1838 //\r
1839         VW_FreeCursor ();\r
1840 \r
1841 //\r
1842 // free map headers and map planes\r
1843 //\r
1844         for (i=0;i<NUMMAPS;i++)\r
1845                 if (mapheaderseg[i])\r
1846                         MM_SetPurge (&(memptr)mapheaderseg[i],3);\r
1847 \r
1848         for (i=0;i<3;i++)\r
1849                 if (mapsegs[i])\r
1850                         MM_FreePtr (&(memptr)mapsegs[i]);\r
1851 \r
1852 //\r
1853 // free sounds\r
1854 //\r
1855         for (i=0;i<NUMSNDCHUNKS;i++)\r
1856                 if (audiosegs[i])\r
1857                         MM_SetPurge (&(memptr)audiosegs[i],3);\r
1858 \r
1859 //\r
1860 // free graphics\r
1861 //\r
1862         CA_FreeGraphics ();\r
1863 }\r
1864 \r
1865 \r
1866 void CA_SetGrPurge (void)\r
1867 {\r
1868         int i;\r
1869 \r
1870 //\r
1871 // free graphics\r
1872 //\r
1873         for (i=0;i<NUMCHUNKS;i++)\r
1874                 if (grsegs[i])\r
1875                         MM_SetPurge (&(memptr)grsegs[i],3);\r
1876 }\r
1877 \r
1878 \r
1879 //===========================================================================\r
1880 \r
1881 \r
1882 /*\r
1883 ======================\r
1884 =\r
1885 = CAL_DialogDraw\r
1886 =\r
1887 ======================\r
1888 */\r
1889 \r
1890 #define NUMBARS (17l*8)\r
1891 #define BARSTEP 8\r
1892 \r
1893 unsigned        thx,thy,lastx;\r
1894 long            barx,barstep;\r
1895 \r
1896 void    CAL_DialogDraw (char *title,unsigned numcache)\r
1897 {\r
1898         unsigned        homex,homey,x;\r
1899 \r
1900         barstep = (NUMBARS<<16)/numcache;\r
1901 \r
1902 //\r
1903 // draw dialog window (masked tiles 12 - 20 are window borders)\r
1904 //\r
1905         US_CenterWindow (20,8);\r
1906         homex = PrintX;\r
1907         homey = PrintY;\r
1908 \r
1909         US_CPrint ("Loading");\r
1910         fontcolor = F_SECONDCOLOR;\r
1911         US_CPrint (title);\r
1912         fontcolor = F_BLACK;\r
1913 \r
1914 //\r
1915 // draw thermometer bar\r
1916 //\r
1917         thx = homex + 8;\r
1918         thy = homey + 32;\r
1919 #ifdef CAT3D\r
1920         VWB_DrawTile8(thx,thy,0);               // CAT3D numbers\r
1921         VWB_DrawTile8(thx,thy+8,3);\r
1922         VWB_DrawTile8(thx,thy+16,6);\r
1923         VWB_DrawTile8(thx+17*8,thy,2);\r
1924         VWB_DrawTile8(thx+17*8,thy+8,5);\r
1925         VWB_DrawTile8(thx+17*8,thy+16,8);\r
1926         for (x=thx+8;x<thx+17*8;x+=8)\r
1927         {\r
1928                 VWB_DrawTile8(x,thy,1);\r
1929                 VWB_DrawTile8(x,thy+8,4);\r
1930                 VWB_DrawTile8(x,thy+16,7);\r
1931         }\r
1932 #else\r
1933         VWB_DrawTile8(thx,thy,11);              // KEEN numbers\r
1934         VWB_DrawTile8(thx,thy+8,14);\r
1935         VWB_DrawTile8(thx,thy+16,17);\r
1936         VWB_DrawTile8(thx+17*8,thy,13);\r
1937         VWB_DrawTile8(thx+17*8,thy+8,16);\r
1938         VWB_DrawTile8(thx+17*8,thy+16,19);\r
1939         for (x=thx+8;x<thx+17*8;x+=8)\r
1940         {\r
1941                 VWB_DrawTile8(x,thy,12);\r
1942                 VWB_DrawTile8(x,thy+8,15);\r
1943                 VWB_DrawTile8(x,thy+16,18);\r
1944         }\r
1945 #endif\r
1946 \r
1947         thx += 4;               // first line location\r
1948         thy += 5;\r
1949         barx = (long)thx<<16;\r
1950         lastx = thx;\r
1951 \r
1952         VW_UpdateScreen();\r
1953 }\r
1954 \r
1955 \r
1956 /*\r
1957 ======================\r
1958 =\r
1959 = CAL_DialogUpdate\r
1960 =\r
1961 ======================\r
1962 */\r
1963 \r
1964 void    CAL_DialogUpdate (void)\r
1965 {\r
1966         unsigned        x,xh;\r
1967 \r
1968         barx+=barstep;\r
1969         xh = barx>>16;\r
1970         if (xh - lastx > BARSTEP)\r
1971         {\r
1972                 for (x=lastx;x<=xh;x++)\r
1973 #if GRMODE == EGAGR\r
1974                         VWB_Vlin (thy,thy+13,x,14);\r
1975 #endif\r
1976 #if GRMODE == CGAGR\r
1977                         VWB_Vlin (thy,thy+13,x,SECONDCOLOR);\r
1978 #endif\r
1979                 lastx = xh;\r
1980                 VW_UpdateScreen();\r
1981         }\r
1982 }\r
1983 \r
1984 /*\r
1985 ======================\r
1986 =\r
1987 = CAL_DialogFinish\r
1988 =\r
1989 ======================\r
1990 */\r
1991 \r
1992 void    CAL_DialogFinish (void)\r
1993 {\r
1994         unsigned        x,xh;\r
1995 \r
1996         xh = thx + NUMBARS;\r
1997         for (x=lastx;x<=xh;x++)\r
1998 #if GRMODE == EGAGR\r
1999                 VWB_Vlin (thy,thy+13,x,14);\r
2000 #endif\r
2001 #if GRMODE == CGAGR\r
2002                 VWB_Vlin (thy,thy+13,x,SECONDCOLOR);\r
2003 #endif\r
2004         VW_UpdateScreen();\r
2005 \r
2006 }\r
2007 \r
2008 //===========================================================================\r
2009 \r
2010 /*\r
2011 ======================\r
2012 =\r
2013 = CA_CacheMarks\r
2014 =\r
2015 ======================\r
2016 */\r
2017 #define MAXEMPTYREAD    1024\r
2018 \r
2019 void CA_CacheMarks (char *title)\r
2020 {\r
2021         boolean dialog;\r
2022         int     i,next,numcache;\r
2023         long    pos,endpos,nextpos,nextendpos,compressed;\r
2024         long    bufferstart,bufferend;  // file position of general buffer\r
2025         byte    far *source;\r
2026         memptr  bigbufferseg;\r
2027 \r
2028         dialog = (title!=NULL);\r
2029 \r
2030         numcache = 0;\r
2031 //\r
2032 // go through and make everything not needed purgable\r
2033 //\r
2034         for (i=0;i<NUMCHUNKS;i++)\r
2035                 if (grneeded[i]&ca_levelbit)\r
2036                 {\r
2037                         if (grsegs[i])                                  // its allready in memory, make\r
2038                                 MM_SetPurge(&grsegs[i],0);      // sure it stays there!\r
2039                         else\r
2040                                 numcache++;\r
2041                 }\r
2042                 else\r
2043                 {\r
2044                         if (grsegs[i])                                  // not needed, so make it purgeable\r
2045                                 MM_SetPurge(&grsegs[i],3);\r
2046                 }\r
2047 \r
2048         if (!numcache)                  // nothing to cache!\r
2049                 return;\r
2050 \r
2051         if (dialog)\r
2052         {\r
2053 #ifdef PROFILE\r
2054                 write(profilehandle,title,strlen(title));\r
2055                 write(profilehandle,"\n",1);\r
2056 #endif\r
2057                 if (drawcachebox)\r
2058                         drawcachebox(title,numcache);\r
2059         }\r
2060 \r
2061 //\r
2062 // go through and load in anything still needed\r
2063 //\r
2064         bufferstart = bufferend = 0;            // nothing good in buffer now\r
2065 \r
2066         for (i=0;i<NUMCHUNKS;i++)\r
2067                 if ( (grneeded[i]&ca_levelbit) && !grsegs[i])\r
2068                 {\r
2069 //\r
2070 // update thermometer\r
2071 //\r
2072                         if (dialog && updatecachebox)\r
2073                                 updatecachebox ();\r
2074 \r
2075                         pos = GRFILEPOS(i);\r
2076                         if (pos<0)\r
2077                                 continue;\r
2078 \r
2079                         next = i +1;\r
2080                         while (GRFILEPOS(next) == -1)           // skip past any sparse tiles\r
2081                                 next++;\r
2082 \r
2083                         compressed = GRFILEPOS(next)-pos;\r
2084                         endpos = pos+compressed;\r
2085 \r
2086                         if (compressed<=BUFFERSIZE)\r
2087                         {\r
2088                                 if (bufferstart<=pos\r
2089                                 && bufferend>= endpos)\r
2090                                 {\r
2091                                 // data is allready in buffer\r
2092                                         source = (byte _seg *)bufferseg+(pos-bufferstart);\r
2093                                 }\r
2094                                 else\r
2095                                 {\r
2096                                 // load buffer with a new block from disk\r
2097                                 // try to get as many of the needed blocks in as possible\r
2098                                         while ( next < NUMCHUNKS )\r
2099                                         {\r
2100                                                 while (next < NUMCHUNKS &&\r
2101                                                 !(grneeded[next]&ca_levelbit && !grsegs[next]))\r
2102                                                         next++;\r
2103                                                 if (next == NUMCHUNKS)\r
2104                                                         continue;\r
2105 \r
2106                                                 nextpos = GRFILEPOS(next);\r
2107                                                 while (GRFILEPOS(++next) == -1) // skip past any sparse tiles\r
2108                                                         ;\r
2109                                                 nextendpos = GRFILEPOS(next);\r
2110                                                 if (nextpos - endpos <= MAXEMPTYREAD\r
2111                                                 && nextendpos-pos <= BUFFERSIZE)\r
2112                                                         endpos = nextendpos;\r
2113                                                 else\r
2114                                                         next = NUMCHUNKS;                       // read pos to posend\r
2115                                         }\r
2116 \r
2117                                         lseek(grhandle,pos,SEEK_SET);\r
2118                                         CA_FarRead(grhandle,bufferseg,endpos-pos);\r
2119                                         bufferstart = pos;\r
2120                                         bufferend = endpos;\r
2121                                         source = bufferseg;\r
2122                                 }\r
2123                         }\r
2124                         else\r
2125                         {\r
2126                         // big chunk, allocate temporary buffer\r
2127                                 MM_GetPtr(&bigbufferseg,compressed);\r
2128                                 if (mmerror)\r
2129                                         return;\r
2130                                 MM_SetLock (&bigbufferseg,true);\r
2131                                 lseek(grhandle,pos,SEEK_SET);\r
2132                                 CA_FarRead(grhandle,bigbufferseg,compressed);\r
2133                                 source = bigbufferseg;\r
2134                         }\r
2135 \r
2136                         CAL_ExpandGrChunk (i,source);\r
2137                         if (mmerror)\r
2138                                 return;\r
2139 \r
2140                         if (compressed>BUFFERSIZE)\r
2141                                 MM_FreePtr(&bigbufferseg);\r
2142 \r
2143                 }\r
2144 \r
2145 //\r
2146 // finish up any thermometer remnants\r
2147 //\r
2148                 if (dialog && finishcachebox)\r
2149                         finishcachebox();\r
2150 }\r
2151 \r