// ID_CA.C // this has been customized for WOLF /* ============================================================================= Id Software Caching Manager --------------------------- Must be started BEFORE the memory manager, because it needs to get the headers loaded into the data segment ============================================================================= */ #include #include "wl_def.h" #pragma hdrstop #define THREEBYTEGRSTARTS /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ typedef struct { word bit0,bit1; // 0-255 is a character, > is a pointer to a node } huffnode; typedef struct { word RLEWtag; int32_t headeroffsets[100]; } mapfiletype; /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ #define BUFFERSIZE 0x1000 static int32_t bufferseg[BUFFERSIZE/4]; int mapon; word *mapsegs[MAPPLANES]; static maptype* mapheaderseg[NUMMAPS]; byte *audiosegs[NUMSNDCHUNKS]; byte *grsegs[NUMCHUNKS]; word RLEWtag; int numEpisodesMissing = 0; /* ============================================================================= LOCAL VARIABLES ============================================================================= */ char extension[5]; // Need a string, not constant to change cache files char graphext[5]; char audioext[5]; static const char gheadname[] = DATADIR "vgahead."; static const char gfilename[] = DATADIR "vgagraph."; static const char gdictname[] = DATADIR "vgadict."; static const char mheadname[] = DATADIR "maphead."; static const char mfilename[] = DATADIR "maptemp."; static const char mfilecama[] = DATADIR "gamemaps."; static const char aheadname[] = DATADIR "audiohed."; static const char afilename[] = DATADIR "audiot."; void CA_CannotOpen(const char *string); static int32_t grstarts[NUMCHUNKS + 1]; static int32_t* audiostarts; // array of offsets in audio / audiot #ifdef GRHEADERLINKED huffnode *grhuffman; #else huffnode grhuffman[255]; #endif int grhandle = -1; // handle to EGAGRAPH int maphandle = -1; // handle to MAPTEMP / GAMEMAPS int audiohandle = -1; // handle to AUDIOT / AUDIO int32_t chunkcomplen,chunkexplen; SDMode oldsoundmode; static int32_t GRFILEPOS(const size_t idx) { assert(idx < lengthof(grstarts)); return grstarts[idx]; } /* ============================================================================= LOW LEVEL ROUTINES ============================================================================= */ /* ============================ = = 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_WriteFile = = Writes a file from a memory buffer = ========================== */ boolean CA_WriteFile (const char *filename, void *ptr, int32_t length) { const int handle = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); if (handle == -1) return false; if (!write (handle,ptr,length)) { close (handle); return false; } close (handle); return true; } /* ========================== = = CA_LoadFile = = Allocate space for and load a file = ========================== */ boolean CA_LoadFile (const char *filename, memptr *ptr) { int32_t size; const int handle = open(filename, O_RDONLY | O_BINARY); if (handle == -1) return false; size = lseek(handle, 0, SEEK_END); lseek(handle, 0, SEEK_SET); *ptr=malloc(size); CHECKMALLOCRESULT(*ptr); if (!read (handle,*ptr,size)) { close (handle); return false; } close (handle); return true; } /* ============================================================================ COMPRESSION routines, see JHUFF.C for more ============================================================================ */ static void CAL_HuffExpand(byte *source, byte *dest, int32_t length, huffnode *hufftable) { byte *end; huffnode *headptr, *huffptr; if(!length || !dest) { Quit("length or dest is null!"); return; } headptr = hufftable+254; // head node is always node 254 int written = 0; end=dest+length; byte val = *source++; byte mask = 1; word nodeval; huffptr = headptr; while(1) { if(!(val & mask)) nodeval = huffptr->bit0; else nodeval = huffptr->bit1; if(mask==0x80) { val = *source++; mask = 1; } else mask <<= 1; if(nodeval<256) { *dest++ = (byte) nodeval; written++; huffptr = headptr; if(dest>=end) break; } else { huffptr = hufftable + (nodeval - 256); } } } /* ====================== = = CAL_CarmackExpand = = Length is the length of the EXPANDED data = ====================== */ #define NEARTAG 0xa7 #define FARTAG 0xa8 void CAL_CarmackExpand (byte *source, word *dest, int length) { word ch,chhigh,count,offset; byte *inptr; word *copyptr, *outptr; length/=2; inptr = (byte *) source; outptr = dest; while (length>0) { ch = READWORD(&inptr); chhigh = ch>>8; if (chhigh == NEARTAG) { count = ch&0xff; if (!count) { // have to insert a word containing the tag byte ch |= *inptr++; *outptr++ = ch; length--; } else { offset = *inptr++; copyptr = outptr - offset; length -= count; if(length<0) return; while (count--) *outptr++ = *copyptr++; } } else if (chhigh == FARTAG) { count = ch&0xff; if (!count) { // have to insert a word containing the tag byte ch |= *inptr++; *outptr++ = ch; length --; } else { offset = READWORD(&inptr); copyptr = dest + offset; length -= count; if(length<0) return; while (count--) *outptr++ = *copyptr++; } } else { *outptr++ = ch; length --; } } } /* ====================== = = CA_RLEWcompress = ====================== */ int32_t CA_RLEWCompress (word *source, int32_t length, word *dest, word rlewtag) { word value,count; unsigned i; word *start,*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 (sourceRLEWtag; // // open the data file // #ifdef CARMACIZED strcpy(fname, mfilecama); strcat(fname, extension); maphandle = open(fname, O_RDONLY | O_BINARY); if (maphandle == -1) CA_CannotOpen(fname); #else strcpy(fname,mfilename); strcat(fname,extension); maphandle = open(fname, O_RDONLY | O_BINARY); if (maphandle == -1) CA_CannotOpen(fname); #endif // // load all map header // for (i=0;iheaderoffsets[i]; if (pos<0) // $FFFFFFFF start is a sparse map continue; mapheaderseg[i]=(maptype *) malloc(sizeof(maptype)); CHECKMALLOCRESULT(mapheaderseg[i]); lseek(maphandle,pos,SEEK_SET); read (maphandle,(memptr)mapheaderseg[i],sizeof(maptype)); } free(tinf); // // allocate space for 3 64*64 planes // for (i=0;icommon.length = READLONGWORD(&ptr); sound->common.priority = READWORD(&ptr); sound->inst.mChar = *ptr++; sound->inst.cChar = *ptr++; sound->inst.mScale = *ptr++; sound->inst.cScale = *ptr++; sound->inst.mAttack = *ptr++; sound->inst.cAttack = *ptr++; sound->inst.mSus = *ptr++; sound->inst.cSus = *ptr++; sound->inst.mWave = *ptr++; sound->inst.cWave = *ptr++; sound->inst.nConn = *ptr++; sound->inst.voice = *ptr++; sound->inst.mode = *ptr++; sound->inst.unused[0] = *ptr++; sound->inst.unused[1] = *ptr++; sound->inst.unused[2] = *ptr++; sound->block = *ptr++; read(audiohandle, sound->data, size - ORIG_ADLIBSOUND_SIZE + 1); // + 1 because of byte data[1] audiosegs[chunk]=(byte *) sound; #endif } //=========================================================================== /* ====================== = = CA_LoadAllSounds = = Purges all sounds, then loads all new ones (mode switch) = ====================== */ void CA_LoadAllSounds (void) { #ifdef SOUND_ENABLE 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;i= STARTTILE8 && chunk < STARTEXTERNS) { // // expanded sizes of tile8/16/32 are implicit // #define BLOCK 64 #define MASKBLOCK 128 if (chunkBUFFERSIZE) free(source); } //========================================================================== /* ====================== = = CA_CacheScreen = = Decompresses a chunk from disk straight onto the screen = ====================== */ void CA_CacheScreen (int chunk) { int32_t pos,compressed,expanded; memptr bigbufferseg; int32_t *source; int next; // // load the chunk into a buffer // pos = GRFILEPOS(chunk); next = chunk +1; while (GRFILEPOS(next) == -1) // skip past any sparse tiles next++; compressed = GRFILEPOS(next)-pos; lseek(grhandle,pos,SEEK_SET); bigbufferseg=malloc(compressed); CHECKMALLOCRESULT(bigbufferseg); read(grhandle,bigbufferseg,compressed); source = (int32_t *) bigbufferseg; expanded = *source++; // // allocate final space, decompress it, and free bigbuffer // Sprites need to have shifts made and various other junk // byte *pic = (byte *) malloc(64000); CHECKMALLOCRESULT(pic); CAL_HuffExpand((byte *) source, pic, expanded, grhuffman); byte *vbuf = LOCK(); for(int y = 0, scy = 0; y < 200; y++, scy += scaleFactor) { for(int x = 0, scx = 0; x < 320; x++, scx += scaleFactor) { byte col = pic[(y * 80 + (x >> 2)) + (x & 3) * 80 * 200]; for(unsigned i = 0; i < scaleFactor; i++) for(unsigned j = 0; j < scaleFactor; j++) vbuf[(scy + i) * curPitch + scx + j] = col; } } UNLOCK(); free(pic); free(bigbufferseg); } //========================================================================== /* ====================== = = CA_CacheMap = = WOLF: This is specialized for a 64*64 map size = ====================== */ void CA_CacheMap (int mapnum) { int32_t pos,compressed; int plane; word *dest; memptr bigbufferseg; unsigned size; word *source; #ifdef CARMACIZED word *buffer2seg; int32_t expanded; #endif mapon = mapnum; // // load the planes into the allready allocated buffers // size = maparea*2; for (plane = 0; planeplanestart[plane]; compressed = mapheaderseg[mapnum]->planelength[plane]; dest = mapsegs[plane]; lseek(maphandle,pos,SEEK_SET); if (compressed<=BUFFERSIZE) source = (word *) bufferseg; else { bigbufferseg=malloc(compressed); CHECKMALLOCRESULT(bigbufferseg); source = (word *) bigbufferseg; } read(maphandle,source,compressed); #ifdef CARMACIZED // // 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++; buffer2seg = (word *) malloc(expanded); CHECKMALLOCRESULT(buffer2seg); CAL_CarmackExpand((byte *) source, buffer2seg,expanded); CA_RLEWexpand(buffer2seg+1,dest,size,RLEWtag); free(buffer2seg); #else // // unRLEW, skipping expanded length // CA_RLEWexpand (source+1,dest,size,RLEWtag); #endif if (compressed>BUFFERSIZE) free(bigbufferseg); } } //=========================================================================== void CA_CannotOpen(const char *string) { char str[30]; strcpy(str,"Can't open "); strcat(str,string); strcat(str,"!\n"); Quit (str); }