OSDN Git Service

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