/* Catacomb Armageddon Source Code * Copyright (C) 1993-2014 Flat Rock Software * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // ID_CA.C /* ============================================================================= Id Software Caching Manager --------------------------- Must be started BEFORE the memory manager, because it needs to get the headers loaded into the data segment ============================================================================= */ #include "LIB_HEAD.H" #pragma hdrstop //#include "ID_STRS.H" #pragma warn -pro #pragma warn -use #define THREEBYTEGRSTARTS /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ typedef struct { unsigned bit0,bit1; // 0-255 is a character, > is a pointer to a node } huffnode; typedef struct { unsigned RLEWtag; long headeroffsets[100]; byte tileinfo[]; } mapfiletype; /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ byte _seg *tinf; int mapon; unsigned _seg *mapsegs[3]; maptype _seg *mapheaderseg[NUMMAPS]; byte _seg *audiosegs[NUMSNDCHUNKS]; void _seg *grsegs[NUMCHUNKS]; byte far grneeded[NUMCHUNKS]; byte ca_levelbit,ca_levelnum; int profilehandle,debughandle; void (*drawcachebox) (char *title, unsigned numcache); void (*updatecachebox) (void); void (*finishcachebox) (void); /* ============================================================================= LOCAL VARIABLES ============================================================================= */ extern long far CGAhead; extern long far EGAhead; extern byte CGAdict; extern byte EGAdict; extern byte far maphead; extern byte mapdict; extern byte far audiohead; extern byte audiodict; long _seg *grstarts; // array of offsets in egagraph, -1 for sparse long _seg *audiostarts; // array of offsets in audio / audiot #ifdef GRHEADERLINKED huffnode *grhuffman; #else huffnode grhuffman[255]; #endif #ifdef AUDIOHEADERLINKED huffnode *audiohuffman; #else huffnode audiohuffman[255]; #endif int grhandle; // handle to EGAGRAPH int maphandle; // handle to MAPTEMP / GAMEMAPS int audiohandle; // handle to AUDIOT / AUDIO long chunkcomplen,chunkexplen; SDMode oldsoundmode; void CAL_DialogDraw (char *title,unsigned numcache); void CAL_DialogUpdate (void); void CAL_DialogFinish (void); void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length); #ifdef THREEBYTEGRSTARTS #define FILEPOSSIZE 3 //#define GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff) long GRFILEPOS(int c) { long value; int offset; offset = c*3; value = *(long far *)(((byte far *)grstarts)+offset); value &= 0x00ffffffl; if (value == 0xffffffl) value = -1; return value; }; #else #define FILEPOSSIZE 4 #define GRFILEPOS(c) (grstarts[c]) #endif /* ============================================================================= LOW LEVEL ROUTINES ============================================================================= */ /* ============================ = = CA_OpenDebug / CA_CloseDebug = = Opens a binary file with the handle "debughandle" = ============================ */ void CA_OpenDebug (void) { unlink ("DEBUG.TXT"); debughandle = open("DEBUG.TXT", O_CREAT | O_WRONLY | O_TEXT); } void CA_CloseDebug (void) { close (debughandle); } /* ============================ = = CAL_GetGrChunkLength = = Gets the length of an explicit length chunk (not tiles) = The file pointer is positioned so the compressed data can be read in next. = ============================ */ void CAL_GetGrChunkLength (int chunk) { lseek(grhandle,GRFILEPOS(chunk),SEEK_SET); read(grhandle,&chunkexplen,sizeof(chunkexplen)); chunkcomplen = GRFILEPOS(chunk+1)-GRFILEPOS(chunk)-4; } /* ========================== = = CA_FarRead = = Read from a file to a far pointer = ========================== */ boolean CA_FarRead (int handle, byte far *dest, long length) { if (length>0xffffl) Quit ("CA_FarRead doesn't support 64K reads yet!"); asm push ds asm mov bx,[handle] asm mov cx,[WORD PTR length] asm mov dx,[WORD PTR dest] asm mov ds,[WORD PTR dest+2] asm mov ah,0x3f // READ w/handle asm int 21h asm pop ds asm jnc good errno = _AX; return false; good: asm cmp ax,[WORD PTR length] asm je done errno = EINVFMT; // user manager knows this is bad read return false; done: return true; } /* ========================== = = CA_SegWrite = = Write from a file to a far pointer = ========================== */ boolean CA_FarWrite (int handle, byte far *source, long length) { if (length>0xffffl) Quit ("CA_FarWrite doesn't support 64K reads yet!"); asm push ds asm mov bx,[handle] asm mov cx,[WORD PTR length] asm mov dx,[WORD PTR source] asm mov ds,[WORD PTR source+2] asm mov ah,0x40 // WRITE w/handle asm int 21h asm pop ds asm jnc good errno = _AX; return false; good: asm cmp ax,[WORD PTR length] asm je done errno = ENOMEM; // user manager knows this is bad write return false; done: return true; } /* ========================== = = CA_ReadFile = = Reads a file into an allready allocated buffer = ========================== */ boolean CA_ReadFile (char *filename, memptr *ptr) { int handle; long size; if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1) return false; size = filelength (handle); if (!CA_FarRead (handle,*ptr,size)) { close (handle); return false; } close (handle); return true; } /* ========================== = = CA_LoadFile = = Allocate space for and load a file = ========================== */ boolean CA_LoadFile (char *filename, memptr *ptr) { int handle; long size; if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1) return false; size = filelength (handle); MM_GetPtr (ptr,size); if (!CA_FarRead (handle,*ptr,size)) { close (handle); return false; } close (handle); return true; } /* ============================================================================ COMPRESSION routines, see JHUFF.C for more ============================================================================ */ /* =============== = = CAL_OptimizeNodes = = Goes through a huffman table and changes the 256-511 node numbers to the = actular address of the node. Must be called before CAL_HuffExpand = =============== */ void CAL_OptimizeNodes (huffnode *table) { huffnode *node; int i; node = table; for (i=0;i<255;i++) { if (node->bit0 >= 256) node->bit0 = (unsigned)(table+(node->bit0-256)); if (node->bit1 >= 256) node->bit1 = (unsigned)(table+(node->bit1-256)); node++; } } /* ====================== = = CAL_HuffExpand = = Length is the length of the EXPANDED data = ====================== */ void CAL_HuffExpand (byte huge *source, byte huge *dest, long length,huffnode *hufftable) { // unsigned bit,byte,node,code; unsigned sourceseg,sourceoff,destseg,destoff,endoff; huffnode *headptr; // huffnode *nodeon; headptr = hufftable+254; // head node is allways node 254 source++; // normalize source--; dest++; dest--; sourceseg = FP_SEG(source); sourceoff = FP_OFF(source); destseg = FP_SEG(dest); destoff = FP_OFF(dest); endoff = destoff+length; // // ds:si source // es:di dest // ss:bx node pointer // if (length <0xfff0) { //-------------------------- // expand less than 64k of data //-------------------------- asm mov bx,[headptr] asm mov si,[sourceoff] asm mov di,[destoff] asm mov es,[destseg] asm mov ds,[sourceseg] asm mov ax,[endoff] asm mov ch,[si] // load first byte asm inc si asm mov cl,1 expandshort: asm test ch,cl // bit set? asm jnz bit1short asm mov dx,[ss:bx] // take bit0 path from node asm shl cl,1 // advance to next bit position asm jc newbyteshort asm jnc sourceupshort bit1short: asm mov dx,[ss:bx+2] // take bit1 path asm shl cl,1 // advance to next bit position asm jnc sourceupshort newbyteshort: asm mov ch,[si] // load next byte asm inc si asm mov cl,1 // back to first bit sourceupshort: asm or dh,dh // if dx<256 its a byte, else move node asm jz storebyteshort asm mov bx,dx // next node = (huffnode *)code asm jmp expandshort storebyteshort: asm mov [es:di],dl asm inc di // write a decopmpressed byte out asm mov bx,[headptr] // back to the head node for next bit asm cmp di,ax // done? asm jne expandshort } else { //-------------------------- // expand more than 64k of data //-------------------------- length--; asm mov bx,[headptr] asm mov cl,1 asm mov si,[sourceoff] asm mov di,[destoff] asm mov es,[destseg] asm mov ds,[sourceseg] asm lodsb // load first byte expand: asm test al,cl // bit set? asm jnz bit1 asm mov dx,[ss:bx] // take bit0 path from node asm jmp gotcode bit1: asm mov dx,[ss:bx+2] // take bit1 path gotcode: asm shl cl,1 // advance to next bit position asm jnc sourceup asm lodsb asm cmp si,0x10 // normalize ds:si asm jb sinorm asm mov cx,ds asm inc cx asm mov ds,cx asm xor si,si sinorm: asm mov cl,1 // back to first bit sourceup: asm or dh,dh // if dx<256 its a byte, else move node asm jz storebyte asm mov bx,dx // next node = (huffnode *)code asm jmp expand storebyte: asm mov [es:di],dl asm inc di // write a decopmpressed byte out asm mov bx,[headptr] // back to the head node for next bit asm cmp di,0x10 // normalize es:di asm jb dinorm asm mov dx,es asm inc dx asm mov es,dx asm xor di,di dinorm: asm sub [WORD PTR ss:length],1 asm jnc expand asm dec [WORD PTR ss:length+2] asm jns expand // when length = ffff ffff, done } asm mov ax,ss asm mov ds,ax } /* ====================== = = CAL_CarmackExpand = = Length is the length of the EXPANDED data = ====================== */ #define NEARTAG 0xa7 #define FARTAG 0xa8 void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length) { unsigned ch,chhigh,count,offset; unsigned far *copyptr, far *inptr, far *outptr; length/=2; inptr = source; outptr = dest; while (length) { ch = *inptr++; chhigh = ch>>8; if (chhigh == NEARTAG) { count = ch&0xff; if (!count) { // have to insert a word containing the tag byte ch |= *((unsigned char far *)inptr)++; *outptr++ = ch; length--; } else { offset = *((unsigned char far *)inptr)++; copyptr = outptr - offset; length -= count; while (count--) *outptr++ = *copyptr++; } } else if (chhigh == FARTAG) { count = ch&0xff; if (!count) { // have to insert a word containing the tag byte ch |= *((unsigned char far *)inptr)++; *outptr++ = ch; length --; } else { offset = *inptr++; copyptr = dest + offset; length -= count; while (count--) *outptr++ = *copyptr++; } } else { *outptr++ = ch; length --; } } } /* ====================== = = CA_RLEWcompress = ====================== */ long CA_RLEWCompress (unsigned huge *source, long length, unsigned huge *dest, unsigned rlewtag) { long complength; unsigned value,count,i; unsigned huge *start,huge *end; start = dest; end = source + (length+1)/2; // // compress it // do { count = 1; value = *source++; while (*source == value && source3 || value == rlewtag) { // // send a tag / count / value string // *dest++ = rlewtag; *dest++ = count; *dest++ = value; } else { // // send word without compressing // for (i=1;i<=count;i++) *dest++ = value; } } while (source0 MM_GetPtr(&(memptr)pictable,NUMPICS*sizeof(pictabletype)); CAL_GetGrChunkLength(STRUCTPIC); // position file pointer MM_GetPtr(&compseg,chunkcomplen); CA_FarRead (grhandle,compseg,chunkcomplen); CAL_HuffExpand (compseg, (byte huge *)pictable,NUMPICS*sizeof(pictabletype),grhuffman); MM_FreePtr(&compseg); #endif #if NUMPICM>0 MM_GetPtr(&(memptr)picmtable,NUMPICM*sizeof(pictabletype)); CAL_GetGrChunkLength(STRUCTPICM); // position file pointer MM_GetPtr(&compseg,chunkcomplen); CA_FarRead (grhandle,compseg,chunkcomplen); CAL_HuffExpand (compseg, (byte huge *)picmtable,NUMPICS*sizeof(pictabletype),grhuffman); MM_FreePtr(&compseg); #endif #if NUMSPRITES>0 MM_GetPtr(&(memptr)spritetable,NUMSPRITES*sizeof(spritetabletype)); CAL_GetGrChunkLength(STRUCTSPRITE); // position file pointer MM_GetPtr(&compseg,chunkcomplen); CA_FarRead (grhandle,compseg,chunkcomplen); CAL_HuffExpand (compseg, (byte huge *)spritetable,NUMSPRITES*sizeof(spritetabletype),grhuffman); MM_FreePtr(&compseg); #endif } //========================================================================== /* ====================== = = CAL_SetupMapFile = ====================== */ void CAL_SetupMapFile (void) { int handle; long length; // // load maphead.ext (offsets and tileinfo for map file) // #ifndef MAPHEADERLINKED if ((handle = open("MAPHEAD."EXT, O_RDONLY | O_BINARY, S_IREAD)) == -1) Quit ("Can't open MAPHEAD."EXT"!"); length = filelength(handle); MM_GetPtr (&(memptr)tinf,length); CA_FarRead(handle, tinf, length); close(handle); #else tinf = (byte _seg *)FP_SEG(&maphead); #endif // // open the data file // #ifdef MAPHEADERLINKED if ((maphandle = open("GAMEMAPS."EXT, O_RDONLY | O_BINARY, S_IREAD)) == -1) Quit ("Can't open GAMEMAPS."EXT"!"); #else if ((maphandle = open("MAPTEMP."EXT, O_RDONLY | O_BINARY, S_IREAD)) == -1) Quit ("Can't open MAPTEMP."EXT"!"); #endif } //========================================================================== /* ====================== = = CAL_SetupAudioFile = ====================== */ void CAL_SetupAudioFile (void) { int handle; long length; // // load maphead.ext (offsets and tileinfo for map file) // #ifndef AUDIOHEADERLINKED if ((handle = open("AUDIOHED."EXT, O_RDONLY | O_BINARY, S_IREAD)) == -1) Quit ("Can't open AUDIOHED."EXT"!"); length = filelength(handle); MM_GetPtr (&(memptr)audiostarts,length); CA_FarRead(handle, (byte far *)audiostarts, length); close(handle); #else audiohuffman = (huffnode *)&audiodict; CAL_OptimizeNodes (audiohuffman); audiostarts = (long _seg *)FP_SEG(&audiohead); #endif // // open the data file // #ifndef AUDIOHEADERLINKED if ((audiohandle = open("AUDIOT."EXT, O_RDONLY | O_BINARY, S_IREAD)) == -1) Quit ("Can't open AUDIOT."EXT"!"); #else if ((audiohandle = open("AUDIO."EXT, O_RDONLY | O_BINARY, S_IREAD)) == -1) Quit ("Can't open AUDIO."EXT"!"); #endif } //========================================================================== /* ====================== = = CA_Startup = = Open all files and load in headers = ====================== */ void CA_Startup (void) { #ifdef PROFILE unlink ("PROFILE.TXT"); profilehandle = open("PROFILE.TXT", O_CREAT | O_WRONLY | O_TEXT); #endif // MDM begin - (GAMERS EDGE) // if (!FindFile("AUDIO."EXT,NULL,2)) Quit("CA_Startup(): Can't find audio files."); // // MDM end #ifndef NOAUDIO CAL_SetupAudioFile (); #endif // MDM begin - (GAMERS EDGE) // if (!FindFile("GAMEMAPS."EXT,NULL,1)) Quit("CA_Startup(): Can't find level files."); // // MDM end #ifndef NOMAPS CAL_SetupMapFile (); #endif // MDM begin - (GAMERS EDGE) // if (!FindFile("EGAGRAPH."EXT,NULL,2)) Quit("CA_Startup(): Can't find graphics files."); // // MDM end #ifndef NOGRAPHICS CAL_SetupGrFile (); #endif mapon = -1; ca_levelbit = 1; ca_levelnum = 0; drawcachebox = CAL_DialogDraw; updatecachebox = CAL_DialogUpdate; finishcachebox = CAL_DialogFinish; } //========================================================================== /* ====================== = = CA_Shutdown = = Closes all files = ====================== */ void CA_Shutdown (void) { #ifdef PROFILE close (profilehandle); #endif close (maphandle); close (grhandle); close (audiohandle); } //=========================================================================== /* ====================== = = CA_CacheAudioChunk = ====================== */ void CA_CacheAudioChunk (int chunk) { long pos,compressed; #ifdef AUDIOHEADERLINKED long expanded; memptr bigbufferseg; byte far *source; #endif if (audiosegs[chunk]) { MM_SetPurge (&(memptr)audiosegs[chunk],0); return; // allready in memory } // MDM begin - (GAMERS EDGE) // if (!FindFile("AUDIO."EXT,NULL,2)) Quit("CA_CacheAudioChunk(): Can't find audio files."); // // MDM end // // load the chunk into a buffer, either the miscbuffer if it fits, or allocate // a larger buffer // pos = audiostarts[chunk]; compressed = audiostarts[chunk+1]-pos; lseek(audiohandle,pos,SEEK_SET); #ifndef AUDIOHEADERLINKED MM_GetPtr (&(memptr)audiosegs[chunk],compressed); if (mmerror) return; CA_FarRead(audiohandle,audiosegs[chunk],compressed); #else if (compressed<=BUFFERSIZE) { CA_FarRead(audiohandle,bufferseg,compressed); source = bufferseg; } else { MM_GetPtr(&bigbufferseg,compressed); if (mmerror) return; MM_SetLock (&bigbufferseg,true); CA_FarRead(audiohandle,bigbufferseg,compressed); source = bigbufferseg; } expanded = *(long far *)source; source += 4; // skip over length MM_GetPtr (&(memptr)audiosegs[chunk],expanded); if (mmerror) goto done; CAL_HuffExpand (source,audiosegs[chunk],expanded,audiohuffman); done: if (compressed>BUFFERSIZE) MM_FreePtr(&bigbufferseg); #endif } //=========================================================================== /* ====================== = = CA_LoadAllSounds = = Purges all sounds, then loads all new ones (mode switch) = ====================== */ void CA_LoadAllSounds (void) { unsigned start,i; switch (oldsoundmode) { case sdm_Off: goto cachein; case sdm_PC: start = STARTPCSOUNDS; break; case sdm_AdLib: start = STARTADLIBSOUNDS; break; } for (i=0;iwidth*spr->height; MM_GetPtr (&grsegs[chunk],smallplane*2+MAXSHIFTS*6); if (mmerror) return; dest = (spritetype _seg *)grsegs[chunk]; dest->sourceoffset[0] = MAXSHIFTS*6; // start data after 3 unsigned tables dest->planesize[0] = smallplane; dest->width[0] = spr->width; // // expand the unshifted shape // CAL_HuffExpand (compressed, &dest->data[0],smallplane*2,grhuffman); #endif #if GRMODE == EGAGR // // calculate sizes // spr = &spritetable[chunk-STARTSPRITES]; smallplane = spr->width*spr->height; bigplane = (spr->width+1)*spr->height; shiftstarts[0] = MAXSHIFTS*6; // start data after 3 unsigned tables shiftstarts[1] = shiftstarts[0] + smallplane*5; // 5 planes in a sprite shiftstarts[2] = shiftstarts[1] + bigplane*5; shiftstarts[3] = shiftstarts[2] + bigplane*5; shiftstarts[4] = shiftstarts[3] + bigplane*5; // nothing ever put here expanded = shiftstarts[spr->shifts]; MM_GetPtr (&grsegs[chunk],expanded); if (mmerror) return; dest = (spritetype _seg *)grsegs[chunk]; // // expand the unshifted shape // CAL_HuffExpand (compressed, &dest->data[0],smallplane*5,grhuffman); // // make the shifts! // switch (spr->shifts) { case 1: for (i=0;i<4;i++) { dest->sourceoffset[i] = shiftstarts[0]; dest->planesize[i] = smallplane; dest->width[i] = spr->width; } break; case 2: for (i=0;i<2;i++) { dest->sourceoffset[i] = shiftstarts[0]; dest->planesize[i] = smallplane; dest->width[i] = spr->width; } for (i=2;i<4;i++) { dest->sourceoffset[i] = shiftstarts[1]; dest->planesize[i] = bigplane; dest->width[i] = spr->width+1; } CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0], dest->sourceoffset[2],spr->width,spr->height,4,true); break; case 4: dest->sourceoffset[0] = shiftstarts[0]; dest->planesize[0] = smallplane; dest->width[0] = spr->width; dest->sourceoffset[1] = shiftstarts[1]; dest->planesize[1] = bigplane; dest->width[1] = spr->width+1; CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0], dest->sourceoffset[1],spr->width,spr->height,2,true); dest->sourceoffset[2] = shiftstarts[2]; dest->planesize[2] = bigplane; dest->width[2] = spr->width+1; CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0], dest->sourceoffset[2],spr->width,spr->height,4,true); dest->sourceoffset[3] = shiftstarts[3]; dest->planesize[3] = bigplane; dest->width[3] = spr->width+1; CAL_ShiftSprite ((unsigned)grsegs[chunk],dest->sourceoffset[0], dest->sourceoffset[3],spr->width,spr->height,6,true); break; default: Quit ("CAL_CacheSprite: Bad shifts number!"); } #endif } //=========================================================================== /* ====================== = = CAL_ExpandGrChunk = = Does whatever is needed with a pointer to a compressed chunk = ====================== */ void CAL_ExpandGrChunk (int chunk, byte far *source) { long expanded; if (chunk >= STARTTILE8 && chunk < STARTEXTERNS) { // // expanded sizes of tile8/16/32 are implicit // #if GRMODE == EGAGR #define BLOCK 32 #define MASKBLOCK 40 #endif #if GRMODE == CGAGR #define BLOCK 16 #define MASKBLOCK 32 #endif if (chunk=STARTSPRITES && chunk< STARTTILE8) CAL_CacheSprite(chunk,source); else { MM_GetPtr (&grsegs[chunk],expanded); if (mmerror) return; CAL_HuffExpand (source,grsegs[chunk],expanded,grhuffman); } } /* ====================== = = CAL_ReadGrChunk = = Gets a chunk off disk, optimizing reads to general buffer = ====================== */ void CAL_ReadGrChunk (int chunk) { long pos,compressed; memptr bigbufferseg; byte far *source; int next; // // load the chunk into a buffer, either the miscbuffer if it fits, or allocate // a larger buffer // pos = GRFILEPOS(chunk); if (pos<0) // $FFFFFFFF start is a sparse tile return; next = chunk +1; while (GRFILEPOS(next) == -1) // skip past any sparse tiles next++; compressed = GRFILEPOS(next)-pos; lseek(grhandle,pos,SEEK_SET); if (compressed<=BUFFERSIZE) { CA_FarRead(grhandle,bufferseg,compressed); source = bufferseg; } else { MM_GetPtr(&bigbufferseg,compressed); if (mmerror) return; MM_SetLock (&bigbufferseg,true); CA_FarRead(grhandle,bigbufferseg,compressed); source = bigbufferseg; } CAL_ExpandGrChunk (chunk,source); if (compressed>BUFFERSIZE) MM_FreePtr(&bigbufferseg); } /* ====================== = = CA_CacheGrChunk = = Makes sure a given chunk is in memory, loadiing it if needed = ====================== */ void CA_CacheGrChunk (int chunk) { long pos,compressed; memptr bigbufferseg; byte far *source; int next; grneeded[chunk] |= ca_levelbit; // make sure it doesn't get removed if (grsegs[chunk]) { MM_SetPurge (&grsegs[chunk],0); return; // allready in memory } // MDM begin - (GAMERS EDGE) // if (!FindFile("EGAGRAPH."EXT,NULL,2)) Quit("CA_CacheGrChunk(): Can't find graphics files."); // // MDM end // // load the chunk into a buffer, either the miscbuffer if it fits, or allocate // a larger buffer // pos = GRFILEPOS(chunk); if (pos<0) // $FFFFFFFF start is a sparse tile return; next = chunk +1; while (GRFILEPOS(next) == -1) // skip past any sparse tiles next++; compressed = GRFILEPOS(next)-pos; lseek(grhandle,pos,SEEK_SET); if (compressed<=BUFFERSIZE) { CA_FarRead(grhandle,bufferseg,compressed); source = bufferseg; } else { MM_GetPtr(&bigbufferseg,compressed); MM_SetLock (&bigbufferseg,true); CA_FarRead(grhandle,bigbufferseg,compressed); source = bigbufferseg; } CAL_ExpandGrChunk (chunk,source); if (compressed>BUFFERSIZE) MM_FreePtr(&bigbufferseg); } //========================================================================== /* ====================== = = CA_CacheMap = ====================== */ void CA_CacheMap (int mapnum) { long pos,compressed; int plane; memptr *dest,bigbufferseg; unsigned size; unsigned far *source; #ifdef MAPHEADERLINKED memptr buffer2seg; long expanded; #endif // MDM begin - (GAMERS EDGE) // if (!FindFile("GAMEMAPS."EXT,NULL,1)) Quit("CA_CacheMap(): Can't find level files."); // // MDM end // // free up memory from last map // if (mapon>-1 && mapheaderseg[mapon]) MM_SetPurge (&(memptr)mapheaderseg[mapon],3); for (plane=0;planeheaderoffsets[mapnum]; if (pos<0) // $FFFFFFFF start is a sparse map Quit ("CA_CacheMap: Tried to load a non existent map!"); MM_GetPtr(&(memptr)mapheaderseg[mapnum],sizeof(maptype)); lseek(maphandle,pos,SEEK_SET); CA_FarRead (maphandle,(memptr)mapheaderseg[mapnum],sizeof(maptype)); } else MM_SetPurge (&(memptr)mapheaderseg[mapnum],0); // // load the planes in // If a plane's pointer still exists it will be overwritten (levels are // allways reloaded, never cached) // size = mapheaderseg[mapnum]->width * mapheaderseg[mapnum]->height * 2; for (plane = 0; planeplanestart[plane]; compressed = mapheaderseg[mapnum]->planelength[plane]; if (!compressed) continue; // the plane is not used in this game dest = &(memptr)mapsegs[plane]; MM_GetPtr(dest,size); lseek(maphandle,pos,SEEK_SET); if (compressed<=BUFFERSIZE) source = bufferseg; else { MM_GetPtr(&bigbufferseg,compressed); MM_SetLock (&bigbufferseg,true); source = bigbufferseg; } CA_FarRead(maphandle,(byte far *)source,compressed); #ifdef MAPHEADERLINKED // // unhuffman, then unRLEW // The huffman'd chunk has a two byte expanded length first // The resulting RLEW chunk also does, even though it's not really // needed // expanded = *source; source++; MM_GetPtr (&buffer2seg,expanded); CAL_CarmackExpand (source, (unsigned far *)buffer2seg,expanded); CA_RLEWexpand (((unsigned far *)buffer2seg)+1,*dest,size, ((mapfiletype _seg *)tinf)->RLEWtag); MM_FreePtr (&buffer2seg); #else // // unRLEW, skipping expanded length // CA_RLEWexpand (source+1, *dest,size, ((mapfiletype _seg *)tinf)->RLEWtag); #endif if (compressed>BUFFERSIZE) MM_FreePtr(&bigbufferseg); } } //=========================================================================== /* ====================== = = CA_UpLevel = = Goes up a bit level in the needed lists and clears it out. = Everything is made purgable = ====================== */ void CA_UpLevel (void) { if (ca_levelnum==7) Quit ("CA_UpLevel: Up past level 7!"); ca_levelbit<<=1; ca_levelnum++; } //=========================================================================== /* ====================== = = CA_DownLevel = = Goes down a bit level in the needed lists and recaches = everything from the lower level = ====================== */ void CA_DownLevel (void) { if (!ca_levelnum) Quit ("CA_DownLevel: Down past level 0!"); ca_levelbit>>=1; ca_levelnum--; CA_CacheMarks(NULL); } //=========================================================================== /* ====================== = = CA_ClearMarks = = Clears out all the marks at the current level = ====================== */ void CA_ClearMarks (void) { int i; for (i=0;i>16; if (xh - lastx > BARSTEP) { for (x=lastx;x<=xh;x++) #if GRMODE == EGAGR VWB_Vlin (thy,thy+13,x,14); #endif #if GRMODE == CGAGR VWB_Vlin (thy,thy+13,x,SECONDCOLOR); #endif lastx = xh; VW_UpdateScreen(); } } /* ====================== = = CAL_DialogFinish = ====================== */ void CAL_DialogFinish (void) { unsigned x,xh; xh = thx + NUMBARS; for (x=lastx;x<=xh;x++) #if GRMODE == EGAGR VWB_Vlin (thy,thy+13,x,14); #endif #if GRMODE == CGAGR VWB_Vlin (thy,thy+13,x,SECONDCOLOR); #endif VW_UpdateScreen(); } //=========================================================================== /* ====================== = = CA_CacheMarks = ====================== */ #define MAXEMPTYREAD 1024 void CA_CacheMarks (char *title) { boolean dialog; int i,next,numcache; long pos,endpos,nextpos,nextendpos,compressed; long bufferstart,bufferend; // file position of general buffer byte far *source; memptr bigbufferseg; dialog = (title!=NULL); numcache = 0; // // go through and make everything not needed purgable // for (i=0;i= endpos) { // data is allready in buffer source = (byte _seg *)bufferseg+(pos-bufferstart); } else { // load buffer with a new block from disk // try to get as many of the needed blocks in as possible while ( next < NUMCHUNKS ) { while (next < NUMCHUNKS && !(grneeded[next]&ca_levelbit && !grsegs[next])) next++; if (next == NUMCHUNKS) continue; nextpos = GRFILEPOS(next); while (GRFILEPOS(++next) == -1) // skip past any sparse tiles ; nextendpos = GRFILEPOS(next); if (nextpos - endpos <= MAXEMPTYREAD && nextendpos-pos <= BUFFERSIZE) endpos = nextendpos; else next = NUMCHUNKS; // read pos to posend } lseek(grhandle,pos,SEEK_SET); CA_FarRead(grhandle,bufferseg,endpos-pos); bufferstart = pos; bufferend = endpos; source = bufferseg; } } else { // big chunk, allocate temporary buffer MM_GetPtr(&bigbufferseg,compressed); if (mmerror) return; MM_SetLock (&bigbufferseg,true); lseek(grhandle,pos,SEEK_SET); CA_FarRead(grhandle,bigbufferseg,compressed); source = bigbufferseg; } CAL_ExpandGrChunk (i,source); if (mmerror) return; if (compressed>BUFFERSIZE) MM_FreePtr(&bigbufferseg); } // // finish up any thermometer remnants // if (dialog && finishcachebox) finishcachebox(); }