--- /dev/null
+// ID_CA.C\r
+\r
+// this has been customized for WOLF\r
+\r
+/*\r
+=============================================================================\r
+\r
+Id Software Caching Manager\r
+---------------------------\r
+\r
+Must be started BEFORE the memory manager, because it needs to get the headers\r
+loaded into the data segment\r
+\r
+=============================================================================\r
+*/\r
+\r
+#include "ID_HEADS.H"\r
+#pragma hdrstop\r
+\r
+#pragma warn -pro\r
+#pragma warn -use\r
+\r
+#define THREEBYTEGRSTARTS\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+typedef struct\r
+{\r
+ unsigned bit0,bit1; // 0-255 is a character, > is a pointer to a node\r
+} huffnode;\r
+\r
+\r
+typedef struct\r
+{\r
+ unsigned RLEWtag;\r
+ long headeroffsets[100];\r
+ byte tileinfo[];\r
+} mapfiletype;\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+byte _seg *tinf;\r
+int mapon;\r
+\r
+unsigned _seg *mapsegs[MAPPLANES];\r
+maptype _seg *mapheaderseg[NUMMAPS];\r
+byte _seg *audiosegs[NUMSNDCHUNKS];\r
+void _seg *grsegs[NUMCHUNKS];\r
+\r
+byte far grneeded[NUMCHUNKS];\r
+byte ca_levelbit,ca_levelnum;\r
+\r
+int profilehandle,debughandle;\r
+\r
+char audioname[13]="AUDIO.";\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+extern long far CGAhead;\r
+extern long far EGAhead;\r
+extern byte CGAdict;\r
+extern byte EGAdict;\r
+extern byte far maphead;\r
+extern byte mapdict;\r
+extern byte far audiohead;\r
+extern byte audiodict;\r
+\r
+\r
+char extension[5], // Need a string, not constant to change cache files\r
+ gheadname[10]=GREXT"HEAD.",\r
+ gfilename[10]=GREXT"GRAPH.",\r
+ gdictname[10]=GREXT"DICT.",\r
+ mheadname[10]="MAPHEAD.",\r
+ mfilename[10]="MAPTEMP.",\r
+ aheadname[10]="AUDIOHED.",\r
+ afilename[10]="AUDIOT.";\r
+\r
+void CA_CannotOpen(char *string);\r
+\r
+long _seg *grstarts; // array of offsets in egagraph, -1 for sparse\r
+long _seg *audiostarts; // array of offsets in audio / audiot\r
+\r
+#ifdef GRHEADERLINKED\r
+huffnode *grhuffman;\r
+#else\r
+huffnode grhuffman[255];\r
+#endif\r
+\r
+#ifdef AUDIOHEADERLINKED\r
+huffnode *audiohuffman;\r
+#else\r
+huffnode audiohuffman[255];\r
+#endif\r
+\r
+\r
+int grhandle; // handle to EGAGRAPH\r
+int maphandle; // handle to MAPTEMP / GAMEMAPS\r
+int audiohandle; // handle to AUDIOT / AUDIO\r
+\r
+long chunkcomplen,chunkexplen;\r
+\r
+SDMode oldsoundmode;\r
+\r
+\r
+\r
+void CAL_CarmackExpand (unsigned far *source, unsigned far *dest,\r
+ unsigned length);\r
+\r
+\r
+#ifdef THREEBYTEGRSTARTS\r
+#define FILEPOSSIZE 3\r
+//#define GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff)\r
+long GRFILEPOS(int c)\r
+{\r
+ long value;\r
+ int offset;\r
+\r
+ offset = c*3;\r
+\r
+ value = *(long far *)(((byte far *)grstarts)+offset);\r
+\r
+ value &= 0x00ffffffl;\r
+\r
+ if (value == 0xffffffl)\r
+ value = -1;\r
+\r
+ return value;\r
+};\r
+#else\r
+#define FILEPOSSIZE 4\r
+#define GRFILEPOS(c) (grstarts[c])\r
+#endif\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOW LEVEL ROUTINES\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+============================\r
+=\r
+= CA_OpenDebug / CA_CloseDebug\r
+=\r
+= Opens a binary file with the handle "debughandle"\r
+=\r
+============================\r
+*/\r
+\r
+void CA_OpenDebug (void)\r
+{\r
+ unlink ("DEBUG.TXT");\r
+ debughandle = open("DEBUG.TXT", O_CREAT | O_WRONLY | O_TEXT);\r
+}\r
+\r
+void CA_CloseDebug (void)\r
+{\r
+ close (debughandle);\r
+}\r
+\r
+\r
+\r
+/*\r
+============================\r
+=\r
+= CAL_GetGrChunkLength\r
+=\r
+= Gets the length of an explicit length chunk (not tiles)\r
+= The file pointer is positioned so the compressed data can be read in next.\r
+=\r
+============================\r
+*/\r
+\r
+void CAL_GetGrChunkLength (int chunk)\r
+{\r
+ lseek(grhandle,GRFILEPOS(chunk),SEEK_SET);\r
+ read(grhandle,&chunkexplen,sizeof(chunkexplen));\r
+ chunkcomplen = GRFILEPOS(chunk+1)-GRFILEPOS(chunk)-4;\r
+}\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= CA_FarRead\r
+=\r
+= Read from a file to a far pointer\r
+=\r
+==========================\r
+*/\r
+\r
+boolean CA_FarRead (int handle, byte far *dest, long length)\r
+{\r
+ boolean flag=false;\r
+ if (length>0xffffl)\r
+ Quit ("CA_FarRead doesn't support 64K reads yet!");\r
+\r
+ __asm {\r
+ push ds\r
+ mov bx,[handle]\r
+ mov cx,[WORD PTR length]\r
+ mov dx,[WORD PTR dest]\r
+ mov ds,[WORD PTR dest+2]\r
+ mov ah,0x3f // READ w/handle\r
+ int 21h\r
+ pop ds\r
+ jnc good\r
+ mov errno,ax\r
+ mov flag,0\r
+ jmp End\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+good:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ cmp ax,[WORD PTR length]\r
+ je done\r
+// errno = EINVFMT; // user manager knows this is bad read\r
+ mov flag,0\r
+ jmp End\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+done:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov flag,1\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+End:\r
+#ifdef __WATCOMC__\r
+ }\r
+#endif\r
+ return flag;\r
+}\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= CA_SegWrite\r
+=\r
+= Write from a file to a far pointer\r
+=\r
+==========================\r
+*/\r
+\r
+boolean CA_FarWrite (int handle, byte far *source, long length)\r
+{\r
+ boolean flag=false;\r
+ if (length>0xffffl)\r
+ Quit ("CA_FarWrite doesn't support 64K reads yet!");\r
+\r
+ __asm {\r
+ push ds\r
+ mov bx,[handle]\r
+ mov cx,[WORD PTR length]\r
+ mov dx,[WORD PTR source]\r
+ mov ds,[WORD PTR source+2]\r
+ mov ah,0x40 // WRITE w/handle\r
+ int 21h\r
+ pop ds\r
+ jnc good\r
+ mov errno,ax\r
+ mov flag,0\r
+ jmp End\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+good:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ cmp ax,[WORD PTR length]\r
+ je done\r
+// errno = ENOMEM; // user manager knows this is bad write\r
+ mov flag,0\r
+ jmp End\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+done:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov flag,1\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+End:\r
+#ifdef __WATCOMC__\r
+ }\r
+#endif\r
+ return flag;\r
+}\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= CA_ReadFile\r
+=\r
+= Reads a file into an allready allocated buffer\r
+=\r
+==========================\r
+*/\r
+\r
+boolean CA_ReadFile (char *filename, memptr *ptr)\r
+{\r
+ int handle;\r
+ long size;\r
+\r
+ if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ return false;\r
+\r
+ size = filelength (handle);\r
+ if (!CA_FarRead (handle,*ptr,size))\r
+ {\r
+ close (handle);\r
+ return false;\r
+ }\r
+ close (handle);\r
+ return true;\r
+}\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= CA_WriteFile\r
+=\r
+= Writes a file from a memory buffer\r
+=\r
+==========================\r
+*/\r
+\r
+boolean CA_WriteFile (char *filename, void far *ptr, long length)\r
+{\r
+ int handle;\r
+ long size;\r
+\r
+ handle = open(filename,O_CREAT | O_BINARY | O_WRONLY,\r
+ S_IREAD | S_IWRITE | S_IFREG);\r
+\r
+ if (handle == -1)\r
+ return false;\r
+\r
+ if (!CA_FarWrite (handle,ptr,length))\r
+ {\r
+ close (handle);\r
+ return false;\r
+ }\r
+ close (handle);\r
+ return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+==========================\r
+=\r
+= CA_LoadFile\r
+=\r
+= Allocate space for and load a file\r
+=\r
+==========================\r
+*/\r
+\r
+boolean CA_LoadFile (char *filename, memptr *ptr)\r
+{\r
+ int handle;\r
+ long size;\r
+\r
+ if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ return false;\r
+\r
+ size = filelength (handle);\r
+ MM_GetPtr (ptr,size);\r
+ if (!CA_FarRead (handle,*ptr,size))\r
+ {\r
+ close (handle);\r
+ return false;\r
+ }\r
+ close (handle);\r
+ return true;\r
+}\r
+\r
+/*\r
+============================================================================\r
+\r
+ COMPRESSION routines, see JHUFF.C for more\r
+\r
+============================================================================\r
+*/\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= CAL_OptimizeNodes\r
+=\r
+= Goes through a huffman table and changes the 256-511 node numbers to the\r
+= actular address of the node. Must be called before CAL_HuffExpand\r
+=\r
+===============\r
+*/\r
+\r
+void CAL_OptimizeNodes (huffnode *table)\r
+{\r
+ huffnode *node;\r
+ int i;\r
+\r
+ node = table;\r
+\r
+ for (i=0;i<255;i++)\r
+ {\r
+ if (node->bit0 >= 256)\r
+ node->bit0 = (unsigned)(table+(node->bit0-256));\r
+ if (node->bit1 >= 256)\r
+ node->bit1 = (unsigned)(table+(node->bit1-256));\r
+ node++;\r
+ }\r
+}\r
+\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CAL_HuffExpand\r
+=\r
+= Length is the length of the EXPANDED data\r
+= If screenhack, the data is decompressed in four planes directly\r
+= to the screen\r
+=\r
+======================\r
+*/\r
+\r
+void CAL_HuffExpand (byte huge *source, byte huge *dest,\r
+ long length,huffnode *hufftable, boolean screenhack)\r
+{\r
+// unsigned bit,byte,node,code;\r
+ unsigned sourceseg,sourceoff,destseg,destoff,endoff;\r
+ huffnode *headptr;\r
+ byte mapmask;\r
+// huffnode *nodeon;\r
+\r
+ headptr = hufftable+254; // head node is allways node 254\r
+\r
+ source++; // normalize\r
+ source--;\r
+ dest++;\r
+ dest--;\r
+\r
+ if (screenhack)\r
+ {\r
+ mapmask = 1;\r
+asm mov dx,SC_INDEX\r
+asm mov ax,SC_MAPMASK + 256\r
+asm out dx,ax\r
+ length >>= 2;\r
+ }\r
+\r
+ sourceseg = FP_SEG(source);\r
+ sourceoff = FP_OFF(source);\r
+ destseg = FP_SEG(dest);\r
+ destoff = FP_OFF(dest);\r
+ endoff = destoff+length;\r
+\r
+//\r
+// ds:si source\r
+// es:di dest\r
+// ss:bx node pointer\r
+//\r
+\r
+ if (length <0xfff0)\r
+ {\r
+\r
+//--------------------------\r
+// expand less than 64k of data\r
+//--------------------------\r
+\r
+ __asm {\r
+ mov bx,[word ptr headptr]\r
+\r
+ mov si,[sourceoff]\r
+ mov di,[destoff]\r
+ mov es,[destseg]\r
+ mov ds,[sourceseg]\r
+ mov ax,[endoff]\r
+\r
+ mov ch,[si] // load first byte\r
+ inc si\r
+ mov cl,1\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+expandshort:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ test ch,cl // bit set?\r
+ jnz bit1short\r
+ mov dx,[ss:bx] // take bit0 path from node\r
+ shl cl,1 // advance to next bit position\r
+ jc newbyteshort\r
+ jnc sourceupshort\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+bit1short:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov dx,[ss:bx+2] // take bit1 path\r
+ shl cl,1 // advance to next bit position\r
+ jnc sourceupshort\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+newbyteshort:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov ch,[si] // load next byte\r
+ inc si\r
+ mov cl,1 // back to first bit\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+sourceupshort:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ or dh,dh // if dx<256 its a byte, else move node\r
+ jz storebyteshort\r
+ mov bx,dx // next node = (huffnode *)code\r
+ jmp expandshort\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+storebyteshort:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov [es:di],dl\r
+ inc di // write a decopmpressed byte out\r
+ mov bx,[word ptr headptr] // back to the head node for next bit\r
+\r
+ cmp di,ax // done?\r
+ jne expandshort\r
+//\r
+// perform screenhack if needed\r
+//\r
+ test [screenhack],1\r
+ jz notscreen\r
+ shl [mapmask],1\r
+ mov ah,[mapmask]\r
+ cmp ah,16\r
+ je notscreen // all four planes done\r
+ mov dx,SC_INDEX\r
+ mov al,SC_MAPMASK\r
+ out dx,ax\r
+ mov di,[destoff]\r
+ mov ax,[endoff]\r
+ jmp expandshort\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+notscreen:\r
+#ifdef __WATCOMC__\r
+ }\r
+#endif\r
+ }\r
+ else\r
+ {\r
+\r
+//--------------------------\r
+// expand more than 64k of data\r
+//--------------------------\r
+\r
+ length--;\r
+\r
+ __asm {\r
+ mov bx,[word ptr headptr]\r
+ mov cl,1\r
+\r
+ mov si,[sourceoff]\r
+ mov di,[destoff]\r
+ mov es,[destseg]\r
+ mov ds,[sourceseg]\r
+\r
+ lodsb // load first byte\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+expand:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ test al,cl // bit set?\r
+ jnz bit1\r
+ mov dx,[ss:bx] // take bit0 path from node\r
+ jmp gotcode\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+bit1:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov dx,[ss:bx+2] // take bit1 path\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+gotcode:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ shl cl,1 // advance to next bit position\r
+ jnc sourceup\r
+ lodsb\r
+ cmp si,0x10 // normalize ds:si\r
+ jb sinorm\r
+ mov cx,ds\r
+ inc cx\r
+ mov ds,cx\r
+ xor si,si\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+sinorm:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov cl,1 // back to first bit\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+sourceup:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ or dh,dh // if dx<256 its a byte, else move node\r
+ jz storebyte\r
+ mov bx,dx // next node = (huffnode *)code\r
+ jmp expand\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+storebyte:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ mov [es:di],dl\r
+ inc di // write a decopmpressed byte out\r
+ mov bx,[word ptr headptr] // back to the head node for next bit\r
+\r
+ cmp di,0x10 // normalize es:di\r
+ jb dinorm\r
+ mov dx,es\r
+ inc dx\r
+ mov es,dx\r
+ xor di,di\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+dinorm:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ sub [WORD PTR ss:length],1\r
+ jnc expand\r
+ dec [WORD PTR ss:length+2]\r
+ jns expand // when length = ffff ffff, done\r
+ }\r
+ }\r
+\r
+ __asm {\r
+ mov ax,ss\r
+ mov ds,ax\r
+ }\r
+\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CAL_CarmackExpand\r
+=\r
+= Length is the length of the EXPANDED data\r
+=\r
+======================\r
+*/\r
+\r
+#define NEARTAG 0xa7\r
+#define FARTAG 0xa8\r
+\r
+void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length)\r
+{\r
+ unsigned ch,chhigh,count,offset;\r
+ unsigned far *copyptr, far *inptr, far *outptr;\r
+\r
+ length/=2;\r
+\r
+ inptr = source;\r
+ outptr = dest;\r
+\r
+ while (length)\r
+ {\r
+ ch = *inptr++;\r
+ chhigh = ch>>8;\r
+ if (chhigh == NEARTAG)\r
+ {\r
+ count = ch&0xff;\r
+ if (!count)\r
+ { // have to insert a word containing the tag byte\r
+ ch |= *(BYTEFARPTRCONV inptr)++;\r
+ *outptr++ = ch;\r
+ length--;\r
+ }\r
+ else\r
+ {\r
+ offset = *(BYTEFARPTRCONV inptr)++;\r
+ copyptr = outptr - offset;\r
+ length -= count;\r
+ while (count--)\r
+ *outptr++ = *copyptr++;\r
+ }\r
+ }\r
+ else if (chhigh == FARTAG)\r
+ {\r
+ count = ch&0xff;\r
+ if (!count)\r
+ { // have to insert a word containing the tag byte\r
+ ch |= *(BYTEFARPTRCONV inptr)++;\r
+ *outptr++ = ch;\r
+ length --;\r
+ }\r
+ else\r
+ {\r
+ offset = *inptr++;\r
+ copyptr = dest + offset;\r
+ length -= count;\r
+ while (count--)\r
+ *outptr++ = *copyptr++;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ *outptr++ = ch;\r
+ length --;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_RLEWcompress\r
+=\r
+======================\r
+*/\r
+\r
+long CA_RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,\r
+ unsigned rlewtag)\r
+{\r
+ long complength;\r
+ unsigned value,count,i;\r
+ unsigned huge *start,huge *end;\r
+\r
+ start = dest;\r
+\r
+ end = source + (length+1)/2;\r
+\r
+//\r
+// compress it\r
+//\r
+ do\r
+ {\r
+ count = 1;\r
+ value = *source++;\r
+ while (*source == value && source<end)\r
+ {\r
+ count++;\r
+ source++;\r
+ }\r
+ if (count>3 || value == rlewtag)\r
+ {\r
+ //\r
+ // send a tag / count / value string\r
+ //\r
+ *dest++ = rlewtag;\r
+ *dest++ = count;\r
+ *dest++ = value;\r
+ }\r
+ else\r
+ {\r
+ //\r
+ // send word without compressing\r
+ //\r
+ for (i=1;i<=count;i++)\r
+ *dest++ = value;\r
+ }\r
+\r
+ } while (source<end);\r
+\r
+ complength = 2*(dest-start);\r
+ return complength;\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_RLEWexpand\r
+= length is EXPANDED length\r
+=\r
+======================\r
+*/\r
+\r
+void CA_RLEWexpand (unsigned huge *source, unsigned huge *dest,long length,\r
+ unsigned rlewtag)\r
+{\r
+// unsigned value,count,i;\r
+ unsigned huge *end;\r
+ unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;\r
+\r
+\r
+//\r
+// expand it\r
+//\r
+#if 0\r
+ do\r
+ {\r
+ value = *source++;\r
+ if (value != rlewtag)\r
+ //\r
+ // uncompressed\r
+ //\r
+ *dest++=value;\r
+ else\r
+ {\r
+ //\r
+ // compressed string\r
+ //\r
+ count = *source++;\r
+ value = *source++;\r
+ for (i=1;i<=count;i++)\r
+ *dest++ = value;\r
+ }\r
+ } while (dest<end);\r
+#endif\r
+\r
+ end = dest + (length)/2;\r
+ sourceseg = FP_SEG(source);\r
+ sourceoff = FP_OFF(source);\r
+ destseg = FP_SEG(dest);\r
+ destoff = FP_OFF(dest);\r
+ endseg = FP_SEG(end);\r
+ endoff = FP_OFF(end);\r
+\r
+\r
+//\r
+// ax = source value\r
+// bx = tag value\r
+// cx = repeat counts\r
+// dx = scratch\r
+//\r
+// NOTE: A repeat count that produces 0xfff0 bytes can blow this!\r
+//\r
+\r
+ __asm {\r
+ mov bx,rlewtag\r
+ mov si,sourceoff\r
+ mov di,destoff\r
+ mov es,destseg\r
+ mov ds,sourceseg\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+expand:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ lodsw\r
+ cmp ax,bx\r
+ je repeat\r
+ stosw\r
+ jmp next\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+repeat:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ lodsw\r
+ mov cx,ax // repeat count\r
+ lodsw // repeat value\r
+ rep stosw\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+next:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ cmp si,0x10 // normalize ds:si\r
+ jb sinorm\r
+ mov ax,si\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ mov dx,ds\r
+ add dx,ax\r
+ mov ds,dx\r
+ and si,0xf\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+sinorm:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ cmp di,0x10 // normalize es:di\r
+ jb dinorm\r
+ mov ax,di\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ shr ax,1\r
+ mov dx,es\r
+ add dx,ax\r
+ mov es,dx\r
+ and di,0xf\r
+#ifdef __BORLANDC__\r
+ }\r
+#endif\r
+dinorm:\r
+#ifdef __BORLANDC__\r
+ __asm {\r
+#endif\r
+ cmp di,ss:endoff\r
+ jne expand\r
+ mov ax,es\r
+ cmp ax,ss:endseg\r
+ jb expand\r
+\r
+ mov ax,ss\r
+ mov ds,ax\r
+ }\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ CACHE MANAGER ROUTINES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CAL_SetupGrFile\r
+=\r
+======================\r
+*/\r
+\r
+void CAL_SetupGrFile (void)\r
+{\r
+ char fname[13];\r
+ int handle;\r
+ memptr compseg;\r
+\r
+#ifdef GRHEADERLINKED\r
+\r
+ grhuffman = (huffnode *)&EGAdict;\r
+ grstarts = (long _seg *)FP_SEG(&EGAhead);\r
+\r
+ CAL_OptimizeNodes (grhuffman);\r
+\r
+#else\r
+\r
+//\r
+// load ???dict.ext (huffman dictionary for graphics files)\r
+//\r
+\r
+ strcpy(fname,gdictname);\r
+ strcat(fname,extension);\r
+\r
+ if ((handle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+\r
+ read(handle, &grhuffman, sizeof(grhuffman));\r
+ close(handle);\r
+ CAL_OptimizeNodes (grhuffman);\r
+//\r
+// load the data offsets from ???head.ext\r
+//\r
+ MM_GetPtr (MEMPTRCONV grstarts,(NUMCHUNKS+1)*FILEPOSSIZE);\r
+\r
+ strcpy(fname,gheadname);\r
+ strcat(fname,extension);\r
+\r
+ if ((handle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+\r
+ CA_FarRead(handle, (memptr)grstarts, (NUMCHUNKS+1)*FILEPOSSIZE);\r
+\r
+ close(handle);\r
+\r
+\r
+#endif\r
+\r
+//\r
+// Open the graphics file, leaving it open until the game is finished\r
+//\r
+ strcpy(fname,gfilename);\r
+ strcat(fname,extension);\r
+\r
+ grhandle = open(fname, O_RDONLY | O_BINARY);\r
+ if (grhandle == -1)\r
+ CA_CannotOpen(fname);\r
+\r
+\r
+//\r
+// load the pic and sprite headers into the arrays in the data segment\r
+//\r
+ MM_GetPtr(MEMPTRCONV pictable,NUMPICS*sizeof(pictabletype));\r
+ CAL_GetGrChunkLength(STRUCTPIC); // position file pointer\r
+ printf("CAL_SetupGrFile:\n");\r
+ printf(" chunkcomplen size is %lu\n", chunkcomplen);\r
+ MM_GetPtr(MEMPTRANDPERCONV compseg,chunkcomplen);\r
+ CA_FarRead (grhandle,compseg,chunkcomplen);\r
+ CAL_HuffExpand (compseg, (byte huge *)pictable,NUMPICS*sizeof(pictabletype),grhuffman,false);\r
+ MM_FreePtr(MEMPTRANDPERCONV compseg);\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CAL_SetupMapFile\r
+=\r
+======================\r
+*/\r
+\r
+void CAL_SetupMapFile (void)\r
+{\r
+ int i;\r
+ int handle;\r
+ long length,pos;\r
+ char fname[13];\r
+\r
+//\r
+// load maphead.ext (offsets and tileinfo for map file)\r
+//\r
+#ifndef MAPHEADERLINKED\r
+ strcpy(fname,mheadname);\r
+ strcat(fname,extension);\r
+\r
+ if ((handle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+\r
+ length = filelength(handle);\r
+ MM_GetPtr (MEMPTRCONV tinf,length);\r
+ CA_FarRead(handle, tinf, length);\r
+ close(handle);\r
+#else\r
+\r
+ tinf = (byte _seg *)FP_SEG(&maphead);\r
+\r
+#endif\r
+\r
+//\r
+// open the data file\r
+//\r
+#ifdef CARMACIZED\r
+ strcpy(fname,"GAMEMAPS.");\r
+ strcat(fname,extension);\r
+\r
+ if ((maphandle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+#else\r
+ strcpy(fname,mfilename);\r
+ strcat(fname,extension);\r
+\r
+ if ((maphandle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+#endif\r
+\r
+//\r
+// load all map header\r
+//\r
+ for (i=0;i<NUMMAPS;i++)\r
+ {\r
+ pos = ((mapfiletype _seg *)tinf)->headeroffsets[i];\r
+ if (pos<0) // $FFFFFFFF start is a sparse map\r
+ continue;\r
+\r
+ MM_GetPtr(MEMPTRCONV mapheaderseg[i],sizeof(maptype));\r
+ MM_SetLock(MEMPTRCONV mapheaderseg[i],true);\r
+ lseek(maphandle,pos,SEEK_SET);\r
+ CA_FarRead (maphandle,(memptr)mapheaderseg[i],sizeof(maptype));\r
+ }\r
+\r
+//\r
+// allocate space for 3 64*64 planes\r
+//\r
+ for (i=0;i<MAPPLANES;i++)\r
+ {\r
+ MM_GetPtr (MEMPTRCONV mapsegs[i],64*64*2);\r
+ MM_SetLock (MEMPTRCONV mapsegs[i],true);\r
+ }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CAL_SetupAudioFile\r
+=\r
+======================\r
+*/\r
+\r
+void CAL_SetupAudioFile (void)\r
+{\r
+ int handle;\r
+ long length;\r
+ char fname[13];\r
+\r
+//\r
+// load maphead.ext (offsets and tileinfo for map file)\r
+//\r
+#ifndef AUDIOHEADERLINKED\r
+ strcpy(fname,aheadname);\r
+ strcat(fname,extension);\r
+\r
+ if ((handle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+\r
+ length = filelength(handle);\r
+ MM_GetPtr (MEMPTRCONV audiostarts,length);\r
+ CA_FarRead(handle, (byte far *)audiostarts, length);\r
+ close(handle);\r
+#else\r
+ audiohuffman = (huffnode *)&audiodict;\r
+ CAL_OptimizeNodes (audiohuffman);\r
+ audiostarts = (long _seg *)FP_SEG(&audiohead);\r
+#endif\r
+\r
+//\r
+// open the data file\r
+//\r
+#ifndef AUDIOHEADERLINKED\r
+ strcpy(fname,afilename);\r
+ strcat(fname,extension);\r
+\r
+ if ((audiohandle = open(fname,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ CA_CannotOpen(fname);\r
+#else\r
+ if ((audiohandle = open("AUDIO."EXTENSION,\r
+ O_RDONLY | O_BINARY, S_IREAD)) == -1)\r
+ Quit ("Can't open AUDIO."EXTENSION"!");\r
+#endif\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_Startup\r
+=\r
+= Open all files and load in headers\r
+=\r
+======================\r
+*/\r
+\r
+void CA_Startup (void)\r
+{\r
+#ifdef PROFILE\r
+ unlink ("PROFILE.TXT");\r
+ profilehandle = open("PROFILE.TXT", O_CREAT | O_WRONLY | O_TEXT);\r
+#endif\r
+\r
+ CAL_SetupMapFile ();\r
+ CAL_SetupGrFile ();\r
+ CAL_SetupAudioFile ();\r
+\r
+ mapon = -1;\r
+ ca_levelbit = 1;\r
+ ca_levelnum = 0;\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_Shutdown\r
+=\r
+= Closes all files\r
+=\r
+======================\r
+*/\r
+\r
+void CA_Shutdown (void)\r
+{\r
+#ifdef PROFILE\r
+ close (profilehandle);\r
+#endif\r
+\r
+ close (maphandle);\r
+ close (grhandle);\r
+ close (audiohandle);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_CacheAudioChunk\r
+=\r
+======================\r
+*/\r
+\r
+void CA_CacheAudioChunk (int chunk)\r
+{\r
+ long pos,compressed;\r
+#ifdef AUDIOHEADERLINKED\r
+ long expanded;\r
+ memptr bigbufferseg;\r
+ byte far *source;\r
+#endif\r
+\r
+ if (audiosegs[chunk])\r
+ {\r
+ MM_SetPurge (MEMPTRCONV audiosegs[chunk],0);\r
+ return; // allready in memory\r
+ }\r
+\r
+//\r
+// load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
+// a larger buffer\r
+//\r
+ pos = audiostarts[chunk];\r
+ compressed = audiostarts[chunk+1]-pos;\r
+\r
+ lseek(audiohandle,pos,SEEK_SET);\r
+\r
+#ifndef AUDIOHEADERLINKED\r
+\r
+ MM_GetPtr (MEMPTRCONV audiosegs[chunk],compressed);\r
+ if (mmerror)\r
+ return;\r
+\r
+ CA_FarRead(audiohandle,audiosegs[chunk],compressed);\r
+\r
+#else\r
+\r
+ if (compressed<=BUFFERSIZE)\r
+ {\r
+ CA_FarRead(audiohandle,bufferseg,compressed);\r
+ source = bufferseg;\r
+ }\r
+ else\r
+ {\r
+ MM_GetPtr(MEMPTRANDPERCONV bigbufferseg,compressed);\r
+ if (mmerror)\r
+ return;\r
+ MM_SetLock (MEMPTRANDPERCONV bigbufferseg,true);\r
+ CA_FarRead(audiohandle,bigbufferseg,compressed);\r
+ source = bigbufferseg;\r
+ }\r
+\r
+ expanded = *(long far *)source;\r
+ source += 4; // skip over length\r
+ MM_GetPtr (MEMPTRCONV audiosegs[chunk],expanded);\r
+ if (mmerror)\r
+ goto done;\r
+ CAL_HuffExpand (source,audiosegs[chunk],expanded,audiohuffman,false);\r
+\r
+done:\r
+ if (compressed>BUFFERSIZE)\r
+ MM_FreePtr(MEMPTRANDPERCONV bigbufferseg);\r
+#endif\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_LoadAllSounds\r
+=\r
+= Purges all sounds, then loads all new ones (mode switch)\r
+=\r
+======================\r
+*/\r
+\r
+void CA_LoadAllSounds (void)\r
+{\r
+ unsigned start,i;\r
+\r
+ switch (oldsoundmode)\r
+ {\r
+ case sdm_Off:\r
+ goto cachein;\r
+ case sdm_PC:\r
+ start = STARTPCSOUNDS;\r
+ break;\r
+ case sdm_AdLib:\r
+ start = STARTADLIBSOUNDS;\r
+ break;\r
+ }\r
+\r
+ for (i=0;i<NUMSOUNDS;i++,start++)\r
+ if (audiosegs[start])\r
+ MM_SetPurge (MEMPTRCONV audiosegs[start],3); // make purgable\r
+\r
+cachein:\r
+\r
+ switch (SoundMode)\r
+ {\r
+ case sdm_Off:\r
+ return;\r
+ case sdm_PC:\r
+ start = STARTPCSOUNDS;\r
+ break;\r
+ case sdm_AdLib:\r
+ start = STARTADLIBSOUNDS;\r
+ break;\r
+ }\r
+\r
+ for (i=0;i<NUMSOUNDS;i++,start++)\r
+ CA_CacheAudioChunk (start);\r
+\r
+ oldsoundmode = SoundMode;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CAL_ExpandGrChunk\r
+=\r
+= Does whatever is needed with a pointer to a compressed chunk\r
+=\r
+======================\r
+*/\r
+\r
+void CAL_ExpandGrChunk (int chunk, byte far *source)\r
+{\r
+ long expanded;\r
+\r
+\r
+ if (chunk >= STARTTILE8 && chunk < STARTEXTERNS)\r
+ {\r
+ //\r
+ // expanded sizes of tile8/16/32 are implicit\r
+ //\r
+\r
+#define BLOCK 64\r
+#define MASKBLOCK 128\r
+\r
+ if (chunk<STARTTILE8M) // tile 8s are all in one chunk!\r
+ expanded = BLOCK*NUMTILE8;\r
+ else if (chunk<STARTTILE16)\r
+ expanded = MASKBLOCK*NUMTILE8M;\r
+ else if (chunk<STARTTILE16M) // all other tiles are one/chunk\r
+ expanded = BLOCK*4;\r
+ else if (chunk<STARTTILE32)\r
+ expanded = MASKBLOCK*4;\r
+ else if (chunk<STARTTILE32M)\r
+ expanded = BLOCK*16;\r
+ else\r
+ expanded = MASKBLOCK*16;\r
+ }\r
+ else\r
+ {\r
+ //\r
+ // everything else has an explicit size longword\r
+ //\r
+ expanded = *(long far *)source;\r
+ source += 4; // skip over length\r
+ }\r
+\r
+//\r
+// allocate final space, decompress it, and free bigbuffer\r
+// Sprites need to have shifts made and various other junk\r
+//\r
+ MM_GetPtr (&grsegs[chunk],expanded);\r
+ if (mmerror)\r
+ return;\r
+ CAL_HuffExpand (source,grsegs[chunk],expanded,grhuffman,false);\r
+}\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_CacheGrChunk\r
+=\r
+= Makes sure a given chunk is in memory, loadiing it if needed\r
+=\r
+======================\r
+*/\r
+\r
+void CA_CacheGrChunk (int chunk)\r
+{\r
+ long pos,compressed;\r
+ memptr bigbufferseg;\r
+ byte far *source;\r
+ int next;\r
+\r
+ grneeded[chunk] |= ca_levelbit; // make sure it doesn't get removed\r
+ if (grsegs[chunk])\r
+ {\r
+ MM_SetPurge (&grsegs[chunk],0);\r
+ return; // allready in memory\r
+ }\r
+\r
+//\r
+// load the chunk into a buffer, either the miscbuffer if it fits, or allocate\r
+// a larger buffer\r
+//\r
+ pos = GRFILEPOS(chunk);\r
+ if (pos<0) // $FFFFFFFF start is a sparse tile\r
+ return;\r
+\r
+ next = chunk +1;\r
+ while (GRFILEPOS(next) == -1) // skip past any sparse tiles\r
+ next++;\r
+\r
+ compressed = GRFILEPOS(next)-pos;\r
+\r
+ lseek(grhandle,pos,SEEK_SET);\r
+\r
+ if (compressed<=BUFFERSIZE)\r
+ {\r
+ CA_FarRead(grhandle,bufferseg,compressed);\r
+ source = bufferseg;\r
+ }\r
+ else\r
+ {\r
+ MM_GetPtr(MEMPTRANDPERCONV bigbufferseg,compressed);\r
+ MM_SetLock (MEMPTRANDPERCONV bigbufferseg,true);\r
+ CA_FarRead(grhandle,bigbufferseg,compressed);\r
+ source = bigbufferseg;\r
+ }\r
+\r
+ CAL_ExpandGrChunk (chunk,source);\r
+\r
+ if (compressed>BUFFERSIZE)\r
+ MM_FreePtr(MEMPTRANDPERCONV bigbufferseg);\r
+}\r
+\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_CacheScreen\r
+=\r
+= Decompresses a chunk from disk straight onto the screen\r
+=\r
+======================\r
+*/\r
+\r
+void CA_CacheScreen (int chunk)\r
+{\r
+ long pos,compressed,expanded;\r
+ memptr bigbufferseg;\r
+ byte far *source;\r
+ int next;\r
+\r
+//\r
+// load the chunk into a buffer\r
+//\r
+ pos = GRFILEPOS(chunk);\r
+ next = chunk +1;\r
+ while (GRFILEPOS(next) == -1) // skip past any sparse tiles\r
+ next++;\r
+ compressed = GRFILEPOS(next)-pos;\r
+\r
+ lseek(grhandle,pos,SEEK_SET);\r
+\r
+ MM_GetPtr(MEMPTRANDPERCONV bigbufferseg,compressed);\r
+ MM_SetLock (MEMPTRANDPERCONV bigbufferseg,true);\r
+ CA_FarRead(grhandle,bigbufferseg,compressed);\r
+ source = bigbufferseg;\r
+\r
+ expanded = *(long far *)source;\r
+ source += 4; // skip over length\r
+\r
+//\r
+// allocate final space, decompress it, and free bigbuffer\r
+// Sprites need to have shifts made and various other junk\r
+//\r
+ CAL_HuffExpand (source,MK_FP(SCREENSEG,bufferofs),expanded,grhuffman,true);\r
+ VW_MarkUpdateBlock (0,0,319,199);\r
+ MM_FreePtr(MEMPTRANDPERCONV bigbufferseg);\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_CacheMap\r
+=\r
+= WOLF: This is specialized for a 64*64 map size\r
+=\r
+======================\r
+*/\r
+\r
+void CA_CacheMap (int mapnum)\r
+{\r
+ long pos,compressed;\r
+ int plane;\r
+ memptr *dest,bigbufferseg;\r
+ unsigned size;\r
+ unsigned far *source;\r
+#ifdef CARMACIZED\r
+ memptr buffer2seg;\r
+ long expanded;\r
+#endif\r
+\r
+ mapon = mapnum;\r
+\r
+//\r
+// load the planes into the allready allocated buffers\r
+//\r
+ size = 64*64*2;\r
+\r
+ for (plane = 0; plane<MAPPLANES; plane++)\r
+ {\r
+ pos = mapheaderseg[mapnum]->planestart[plane];\r
+ compressed = mapheaderseg[mapnum]->planelength[plane];\r
+\r
+ dest = MEMPTRCONV mapsegs[plane];\r
+\r
+ lseek(maphandle,pos,SEEK_SET);\r
+ if (compressed<=BUFFERSIZE)\r
+ source = bufferseg;\r
+ else\r
+ {\r
+ MM_GetPtr(MEMPTRANDPERCONV bigbufferseg,compressed);\r
+ MM_SetLock (MEMPTRANDPERCONV bigbufferseg,true);\r
+ source = bigbufferseg;\r
+ }\r
+\r
+ CA_FarRead(maphandle,(byte far *)source,compressed);\r
+#ifdef CARMACIZED\r
+ //\r
+ // unhuffman, then unRLEW\r
+ // The huffman'd chunk has a two byte expanded length first\r
+ // The resulting RLEW chunk also does, even though it's not really\r
+ // needed\r
+ //\r
+ expanded = *source;\r
+ source++;\r
+ MM_GetPtr (MEMPTRANDPERCONV buffer2seg,expanded);\r
+ CAL_CarmackExpand (source, (unsigned far *)buffer2seg,expanded);\r
+ CA_RLEWexpand (((unsigned far *)buffer2seg)+1,*dest,size,\r
+ ((mapfiletype _seg *)tinf)->RLEWtag);\r
+ MM_FreePtr (MEMPTRANDPERCONV buffer2seg);\r
+\r
+#else\r
+ //\r
+ // unRLEW, skipping expanded length\r
+ //\r
+ CA_RLEWexpand (source+1, *dest,size,\r
+ ((mapfiletype _seg *)tinf)->RLEWtag);\r
+#endif\r
+\r
+ if (compressed>BUFFERSIZE)\r
+ MM_FreePtr(MEMPTRANDPERCONV bigbufferseg);\r
+ }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_UpLevel\r
+=\r
+= Goes up a bit level in the needed lists and clears it out.\r
+= Everything is made purgable\r
+=\r
+======================\r
+*/\r
+\r
+void CA_UpLevel (void)\r
+{\r
+ int i;\r
+\r
+ if (ca_levelnum==7)\r
+ Quit ("CA_UpLevel: Up past level 7!");\r
+\r
+ for (i=0;i<NUMCHUNKS;i++)\r
+ if (grsegs[i])\r
+ MM_SetPurge (MEMPTRCONV grsegs[i],3);\r
+ ca_levelbit<<=1;\r
+ ca_levelnum++;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_DownLevel\r
+=\r
+= Goes down a bit level in the needed lists and recaches\r
+= everything from the lower level\r
+=\r
+======================\r
+*/\r
+\r
+void CA_DownLevel (void)\r
+{\r
+ if (!ca_levelnum)\r
+ Quit ("CA_DownLevel: Down past level 0!");\r
+ ca_levelbit>>=1;\r
+ ca_levelnum--;\r
+ CA_CacheMarks();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_ClearMarks\r
+=\r
+= Clears out all the marks at the current level\r
+=\r
+======================\r
+*/\r
+\r
+void CA_ClearMarks (void)\r
+{\r
+ int i;\r
+\r
+ for (i=0;i<NUMCHUNKS;i++)\r
+ grneeded[i]&=~ca_levelbit;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_ClearAllMarks\r
+=\r
+= Clears out all the marks on all the levels\r
+=\r
+======================\r
+*/\r
+\r
+void CA_ClearAllMarks (void)\r
+{\r
+ _fmemset (grneeded,0,sizeof(grneeded));\r
+ ca_levelbit = 1;\r
+ ca_levelnum = 0;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_FreeGraphics\r
+=\r
+======================\r
+*/\r
+\r
+\r
+void CA_SetGrPurge (void)\r
+{\r
+ int i;\r
+\r
+//\r
+// free graphics\r
+//\r
+ CA_ClearMarks ();\r
+\r
+ for (i=0;i<NUMCHUNKS;i++)\r
+ if (grsegs[i])\r
+ MM_SetPurge (MEMPTRCONV grsegs[i],3);\r
+}\r
+\r
+\r
+\r
+/*\r
+======================\r
+=\r
+= CA_SetAllPurge\r
+=\r
+= Make everything possible purgable\r
+=\r
+======================\r
+*/\r
+\r
+void CA_SetAllPurge (void)\r
+{\r
+ int i;\r
+\r
+\r
+//\r
+// free sounds\r
+//\r
+ for (i=0;i<NUMSNDCHUNKS;i++)\r
+ if (audiosegs[i])\r
+ MM_SetPurge (MEMPTRCONV audiosegs[i],3);\r
+\r
+//\r
+// free graphics\r
+//\r
+ CA_SetGrPurge ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+======================\r
+=\r
+= CA_CacheMarks\r
+=\r
+======================\r
+*/\r
+#define MAXEMPTYREAD 1024\r
+\r
+void CA_CacheMarks (void)\r
+{\r
+ int i,next,numcache;\r
+ long pos,endpos,nextpos,nextendpos,compressed;\r
+ long bufferstart,bufferend; // file position of general buffer\r
+ byte far *source;\r
+ memptr bigbufferseg;\r
+\r
+ numcache = 0;\r
+//\r
+// go through and make everything not needed purgable\r
+//\r
+ for (i=0;i<NUMCHUNKS;i++)\r
+ if (grneeded[i]&ca_levelbit)\r
+ {\r
+ if (grsegs[i]) // its allready in memory, make\r
+ MM_SetPurge(&grsegs[i],0); // sure it stays there!\r
+ else\r
+ numcache++;\r
+ }\r
+ else\r
+ {\r
+ if (grsegs[i]) // not needed, so make it purgeable\r
+ MM_SetPurge(&grsegs[i],3);\r
+ }\r
+\r
+ if (!numcache) // nothing to cache!\r
+ return;\r
+\r
+\r
+//\r
+// go through and load in anything still needed\r
+//\r
+ bufferstart = bufferend = 0; // nothing good in buffer now\r
+\r
+ for (i=0;i<NUMCHUNKS;i++)\r
+ if ( (grneeded[i]&ca_levelbit) && !grsegs[i])\r
+ {\r
+ pos = GRFILEPOS(i);\r
+ if (pos<0)\r
+ continue;\r
+\r
+ next = i +1;\r
+ while (GRFILEPOS(next) == -1) // skip past any sparse tiles\r
+ next++;\r
+\r
+ compressed = GRFILEPOS(next)-pos;\r
+ endpos = pos+compressed;\r
+\r
+ if (compressed<=BUFFERSIZE)\r
+ {\r
+ if (bufferstart<=pos\r
+ && bufferend>= endpos)\r
+ {\r
+ // data is allready in buffer\r
+ source = (byte _seg *)bufferseg+(pos-bufferstart);\r
+ }\r
+ else\r
+ {\r
+ // load buffer with a new block from disk\r
+ // try to get as many of the needed blocks in as possible\r
+ while ( next < NUMCHUNKS )\r
+ {\r
+ while (next < NUMCHUNKS &&\r
+ !(grneeded[next]&ca_levelbit && !grsegs[next]))\r
+ next++;\r
+ if (next == NUMCHUNKS)\r
+ continue;\r
+\r
+ nextpos = GRFILEPOS(next);\r
+ while (GRFILEPOS(++next) == -1) // skip past any sparse tiles\r
+ ;\r
+ nextendpos = GRFILEPOS(next);\r
+ if (nextpos - endpos <= MAXEMPTYREAD\r
+ && nextendpos-pos <= BUFFERSIZE)\r
+ endpos = nextendpos;\r
+ else\r
+ next = NUMCHUNKS; // read pos to posend\r
+ }\r
+\r
+ lseek(grhandle,pos,SEEK_SET);\r
+ CA_FarRead(grhandle,bufferseg,endpos-pos);\r
+ bufferstart = pos;\r
+ bufferend = endpos;\r
+ source = bufferseg;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // big chunk, allocate temporary buffer\r
+ MM_GetPtr(MEMPTRANDPERCONV bigbufferseg,compressed);\r
+ if (mmerror)\r
+ return;\r
+ MM_SetLock (MEMPTRANDPERCONV bigbufferseg,true);\r
+ lseek(grhandle,pos,SEEK_SET);\r
+ CA_FarRead(grhandle,bigbufferseg,compressed);\r
+ source = bigbufferseg;\r
+ }\r
+\r
+ CAL_ExpandGrChunk (i,source);\r
+ if (mmerror)\r
+ return;\r
+\r
+ if (compressed>BUFFERSIZE)\r
+ MM_FreePtr(MEMPTRANDPERCONV bigbufferseg);\r
+\r
+ }\r
+}\r
+\r
+void CA_CannotOpen(char *string)\r
+{\r
+ char str[30];\r
+\r
+ strcpy(str,"Can't open ");\r
+ strcat(str,string);\r
+ strcat(str,"!\n");\r
+ Quit (str);\r
+}\r