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