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