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