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