X-Git-Url: http://4ch.mooo.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=16%2Fwf3d8086%2Fid_ca.c;fp=16%2Fwf3d8086%2Fid_ca.c;h=142296b2ea9e47bb5ea7737f21d99c3c00edad18;hb=d564176a4080e188751df2ae2363f272c62bf452;hp=0000000000000000000000000000000000000000;hpb=e3dc8b5d9b956b94d22e8e1d8dd13ab4dd912f3a;p=16.git diff --git a/16/wf3d8086/id_ca.c b/16/wf3d8086/id_ca.c new file mode 100755 index 00000000..142296b2 --- /dev/null +++ b/16/wf3d8086/id_ca.c @@ -0,0 +1,1768 @@ +// 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 "ID_HEADS.H" +#pragma hdrstop + +#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[MAPPLANES]; +maptype _seg *mapheaderseg[NUMMAPS]; +byte _seg *audiosegs[NUMSNDCHUNKS]; +void _seg *grsegs[NUMCHUNKS]; + +byte far grneeded[NUMCHUNKS]; +byte ca_levelbit,ca_levelnum; + +int profilehandle,debughandle; + +char audioname[13]="AUDIO."; + +/* +============================================================================= + + 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; + + +char extension[5], // Need a string, not constant to change cache files + gheadname[10]=GREXT"HEAD.", + gfilename[10]=GREXT"GRAPH.", + gdictname[10]=GREXT"DICT.", + mheadname[10]="MAPHEAD.", + mfilename[10]="MAPTEMP.", + aheadname[10]="AUDIOHED.", + afilename[10]="AUDIOT."; + +void CA_CannotOpen(char *string); + +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_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_WriteFile += += Writes a file from a memory buffer += +========================== +*/ + +boolean CA_WriteFile (char *filename, void far *ptr, long length) +{ + int handle; + long size; + + handle = open(filename,O_CREAT | O_BINARY | O_WRONLY, + S_IREAD | S_IWRITE | S_IFREG); + + if (handle == -1) + return false; + + if (!CA_FarWrite (handle,ptr,length)) + { + 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 += If screenhack, the data is decompressed in four planes directly += to the screen += +====================== +*/ + +void CAL_HuffExpand (byte huge *source, byte huge *dest, + long length,huffnode *hufftable, boolean screenhack) +{ +// unsigned bit,byte,node,code; + unsigned sourceseg,sourceoff,destseg,destoff,endoff; + huffnode *headptr; + byte mapmask; +// huffnode *nodeon; + + headptr = hufftable+254; // head node is allways node 254 + + source++; // normalize + source--; + dest++; + dest--; + + if (screenhack) + { + mapmask = 1; +asm mov dx,SC_INDEX +asm mov ax,SC_MAPMASK + 256 +asm out dx,ax + length >>= 2; + } + + 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 + +// +// perform screenhack if needed +// +asm test [screenhack],1 +asm jz notscreen +asm shl [mapmask],1 +asm mov ah,[mapmask] +asm cmp ah,16 +asm je notscreen // all four planes done +asm mov dx,SC_INDEX +asm mov al,SC_MAPMASK +asm out dx,ax +asm mov di,[destoff] +asm mov ax,[endoff] +asm jmp expandshort + +notscreen:; + } + 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 (sourceheaderoffsets[i]; + if (pos<0) // $FFFFFFFF start is a sparse map + continue; + + MM_GetPtr(&(memptr)mapheaderseg[i],sizeof(maptype)); + MM_SetLock(&(memptr)mapheaderseg[i],true); + lseek(maphandle,pos,SEEK_SET); + CA_FarRead (maphandle,(memptr)mapheaderseg[i],sizeof(maptype)); + } + +// +// allocate space for 3 64*64 planes +// + for (i=0;iBUFFERSIZE) + 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;i= STARTTILE8 && chunk < STARTEXTERNS) + { + // + // expanded sizes of tile8/16/32 are implicit + // + +#define BLOCK 64 +#define MASKBLOCK 128 + + if (chunkBUFFERSIZE) + MM_FreePtr(&bigbufferseg); +} + + + +//========================================================================== + +/* +====================== += += CA_CacheScreen += += Decompresses a chunk from disk straight onto the screen += +====================== +*/ + +void CA_CacheScreen (int chunk) +{ + long pos,compressed,expanded; + memptr bigbufferseg; + byte far *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); + + MM_GetPtr(&bigbufferseg,compressed); + MM_SetLock (&bigbufferseg,true); + CA_FarRead(grhandle,bigbufferseg,compressed); + source = bigbufferseg; + + expanded = *(long far *)source; + source += 4; // skip over length + +// +// allocate final space, decompress it, and free bigbuffer +// Sprites need to have shifts made and various other junk +// + CAL_HuffExpand (source,MK_FP(SCREENSEG,bufferofs),expanded,grhuffman,true); + VW_MarkUpdateBlock (0,0,319,199); + MM_FreePtr(&bigbufferseg); +} + +//========================================================================== + +/* +====================== += += CA_CacheMap += += WOLF: This is specialized for a 64*64 map size += +====================== +*/ + +void CA_CacheMap (int mapnum) +{ + long pos,compressed; + int plane; + memptr *dest,bigbufferseg; + unsigned size; + unsigned far *source; +#ifdef CARMACIZED + memptr buffer2seg; + long expanded; +#endif + + mapon = mapnum; + +// +// load the planes into the allready allocated buffers +// + size = 64*64*2; + + for (plane = 0; planeplanestart[plane]; + compressed = mapheaderseg[mapnum]->planelength[plane]; + + dest = &(memptr)mapsegs[plane]; + + 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 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++; + 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) +{ + int i; + + if (ca_levelnum==7) + Quit ("CA_UpLevel: Up past level 7!"); + + for (i=0;i>=1; + ca_levelnum--; + CA_CacheMarks(); +} + +//=========================================================================== + +/* +====================== += += CA_ClearMarks += += Clears out all the marks at the current level += +====================== +*/ + +void CA_ClearMarks (void) +{ + int i; + + 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); + + } +} + +void CA_CannotOpen(char *string) +{ + char str[30]; + + strcpy(str,"Can't open "); + strcat(str,string); + strcat(str,"!\n"); + Quit (str); +} \ No newline at end of file