wolf3d/ID_CA.C

1768 lines
33 KiB
C
Raw Permalink Normal View History

1995-07-21 00:00:00 +00:00
// 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 && source<end)
{
count++;
source++;
}
if (count>3 || 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 (source<end);
complength = 2*(dest-start);
return complength;
}
/*
======================
=
= CA_RLEWexpand
= length is EXPANDED length
=
======================
*/
void CA_RLEWexpand (unsigned huge *source, unsigned huge *dest,long length,
unsigned rlewtag)
{
// unsigned value,count,i;
unsigned huge *end;
unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
//
// expand it
//
#if 0
do
{
value = *source++;
if (value != rlewtag)
//
// uncompressed
//
*dest++=value;
else
{
//
// compressed string
//
count = *source++;
value = *source++;
for (i=1;i<=count;i++)
*dest++ = value;
}
} while (dest<end);
#endif
end = dest + (length)/2;
sourceseg = FP_SEG(source);
sourceoff = FP_OFF(source);
destseg = FP_SEG(dest);
destoff = FP_OFF(dest);
endseg = FP_SEG(end);
endoff = FP_OFF(end);
//
// ax = source value
// bx = tag value
// cx = repeat counts
// dx = scratch
//
// NOTE: A repeat count that produces 0xfff0 bytes can blow this!
//
asm mov bx,rlewtag
asm mov si,sourceoff
asm mov di,destoff
asm mov es,destseg
asm mov ds,sourceseg
expand:
asm lodsw
asm cmp ax,bx
asm je repeat
asm stosw
asm jmp next
repeat:
asm lodsw
asm mov cx,ax // repeat count
asm lodsw // repeat value
asm rep stosw
next:
asm cmp si,0x10 // normalize ds:si
asm jb sinorm
asm mov ax,si
asm shr ax,1
asm shr ax,1
asm shr ax,1
asm shr ax,1
asm mov dx,ds
asm add dx,ax
asm mov ds,dx
asm and si,0xf
sinorm:
asm cmp di,0x10 // normalize es:di
asm jb dinorm
asm mov ax,di
asm shr ax,1
asm shr ax,1
asm shr ax,1
asm shr ax,1
asm mov dx,es
asm add dx,ax
asm mov es,dx
asm and di,0xf
dinorm:
asm cmp di,ss:endoff
asm jne expand
asm mov ax,es
asm cmp ax,ss:endseg
asm jb expand
asm mov ax,ss
asm mov ds,ax
}
/*
=============================================================================
CACHE MANAGER ROUTINES
=============================================================================
*/
/*
======================
=
= CAL_SetupGrFile
=
======================
*/
void CAL_SetupGrFile (void)
{
char fname[13];
int handle;
memptr compseg;
#ifdef GRHEADERLINKED
grhuffman = (huffnode *)&EGAdict;
grstarts = (long _seg *)FP_SEG(&EGAhead);
CAL_OptimizeNodes (grhuffman);
#else
//
// load ???dict.ext (huffman dictionary for graphics files)
//
strcpy(fname,gdictname);
strcat(fname,extension);
if ((handle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
read(handle, &grhuffman, sizeof(grhuffman));
close(handle);
CAL_OptimizeNodes (grhuffman);
//
// load the data offsets from ???head.ext
//
MM_GetPtr (&(memptr)grstarts,(NUMCHUNKS+1)*FILEPOSSIZE);
strcpy(fname,gheadname);
strcat(fname,extension);
if ((handle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
CA_FarRead(handle, (memptr)grstarts, (NUMCHUNKS+1)*FILEPOSSIZE);
close(handle);
#endif
//
// Open the graphics file, leaving it open until the game is finished
//
strcpy(fname,gfilename);
strcat(fname,extension);
grhandle = open(fname, O_RDONLY | O_BINARY);
if (grhandle == -1)
CA_CannotOpen(fname);
//
// load the pic and sprite headers into the arrays in the data segment
//
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,false);
MM_FreePtr(&compseg);
}
//==========================================================================
/*
======================
=
= CAL_SetupMapFile
=
======================
*/
void CAL_SetupMapFile (void)
{
int i;
int handle;
long length,pos;
char fname[13];
//
// load maphead.ext (offsets and tileinfo for map file)
//
#ifndef MAPHEADERLINKED
strcpy(fname,mheadname);
strcat(fname,extension);
if ((handle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
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 CARMACIZED
strcpy(fname,"GAMEMAPS.");
strcat(fname,extension);
if ((maphandle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
#else
strcpy(fname,mfilename);
strcat(fname,extension);
if ((maphandle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
#endif
//
// load all map header
//
for (i=0;i<NUMMAPS;i++)
{
pos = ((mapfiletype _seg *)tinf)->headeroffsets[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;i<MAPPLANES;i++)
{
MM_GetPtr (&(memptr)mapsegs[i],64*64*2);
MM_SetLock (&(memptr)mapsegs[i],true);
}
}
//==========================================================================
/*
======================
=
= CAL_SetupAudioFile
=
======================
*/
void CAL_SetupAudioFile (void)
{
int handle;
long length;
char fname[13];
//
// load maphead.ext (offsets and tileinfo for map file)
//
#ifndef AUDIOHEADERLINKED
strcpy(fname,aheadname);
strcat(fname,extension);
if ((handle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
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
strcpy(fname,afilename);
strcat(fname,extension);
if ((audiohandle = open(fname,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
CA_CannotOpen(fname);
#else
if ((audiohandle = open("AUDIO."EXTENSION,
O_RDONLY | O_BINARY, S_IREAD)) == -1)
Quit ("Can't open AUDIO."EXTENSION"!");
#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
CAL_SetupMapFile ();
CAL_SetupGrFile ();
CAL_SetupAudioFile ();
mapon = -1;
ca_levelbit = 1;
ca_levelnum = 0;
}
//==========================================================================
/*
======================
=
= 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
}
//
// 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,false);
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;i<NUMSOUNDS;i++,start++)
if (audiosegs[start])
MM_SetPurge (&(memptr)audiosegs[start],3); // make purgable
cachein:
switch (SoundMode)
{
case sdm_Off:
return;
case sdm_PC:
start = STARTPCSOUNDS;
break;
case sdm_AdLib:
start = STARTADLIBSOUNDS;
break;
}
for (i=0;i<NUMSOUNDS;i++,start++)
CA_CacheAudioChunk (start);
oldsoundmode = SoundMode;
}
//===========================================================================
/*
======================
=
= 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
//
#define BLOCK 64
#define MASKBLOCK 128
if (chunk<STARTTILE8M) // tile 8s are all in one chunk!
expanded = BLOCK*NUMTILE8;
else if (chunk<STARTTILE16)
expanded = MASKBLOCK*NUMTILE8M;
else if (chunk<STARTTILE16M) // all other tiles are one/chunk
expanded = BLOCK*4;
else if (chunk<STARTTILE32)
expanded = MASKBLOCK*4;
else if (chunk<STARTTILE32M)
expanded = BLOCK*16;
else
expanded = MASKBLOCK*16;
}
else
{
//
// everything else has an explicit size longword
//
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
//
MM_GetPtr (&grsegs[chunk],expanded);
if (mmerror)
return;
CAL_HuffExpand (source,grsegs[chunk],expanded,grhuffman,false);
}
/*
======================
=
= 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
}
//
// 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_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; plane<MAPPLANES; plane++)
{
pos = mapheaderseg[mapnum]->planestart[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<NUMCHUNKS;i++)
if (grsegs[i])
MM_SetPurge (&(memptr)grsegs[i],3);
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();
}
//===========================================================================
/*
======================
=
= CA_ClearMarks
=
= Clears out all the marks at the current level
=
======================
*/
void CA_ClearMarks (void)
{
int i;
for (i=0;i<NUMCHUNKS;i++)
grneeded[i]&=~ca_levelbit;
}
//===========================================================================
/*
======================
=
= CA_ClearAllMarks
=
= Clears out all the marks on all the levels
=
======================
*/
void CA_ClearAllMarks (void)
{
_fmemset (grneeded,0,sizeof(grneeded));
ca_levelbit = 1;
ca_levelnum = 0;
}
//===========================================================================
/*
======================
=
= CA_FreeGraphics
=
======================
*/
void CA_SetGrPurge (void)
{
int i;
//
// free graphics
//
CA_ClearMarks ();
for (i=0;i<NUMCHUNKS;i++)
if (grsegs[i])
MM_SetPurge (&(memptr)grsegs[i],3);
}
/*
======================
=
= CA_SetAllPurge
=
= Make everything possible purgable
=
======================
*/
void CA_SetAllPurge (void)
{
int i;
//
// free sounds
//
for (i=0;i<NUMSNDCHUNKS;i++)
if (audiosegs[i])
MM_SetPurge (&(memptr)audiosegs[i],3);
//
// free graphics
//
CA_SetGrPurge ();
}
//===========================================================================
/*
======================
=
= CA_CacheMarks
=
======================
*/
#define MAXEMPTYREAD 1024
void CA_CacheMarks (void)
{
int i,next,numcache;
long pos,endpos,nextpos,nextendpos,compressed;
long bufferstart,bufferend; // file position of general buffer
byte far *source;
memptr bigbufferseg;
numcache = 0;
//
// go through and make everything not needed purgable
//
for (i=0;i<NUMCHUNKS;i++)
if (grneeded[i]&ca_levelbit)
{
if (grsegs[i]) // its allready in memory, make
MM_SetPurge(&grsegs[i],0); // sure it stays there!
else
numcache++;
}
else
{
if (grsegs[i]) // not needed, so make it purgeable
MM_SetPurge(&grsegs[i],3);
}
if (!numcache) // nothing to cache!
return;
//
// go through and load in anything still needed
//
bufferstart = bufferend = 0; // nothing good in buffer now
for (i=0;i<NUMCHUNKS;i++)
if ( (grneeded[i]&ca_levelbit) && !grsegs[i])
{
pos = GRFILEPOS(i);
if (pos<0)
continue;
next = i +1;
while (GRFILEPOS(next) == -1) // skip past any sparse tiles
next++;
compressed = GRFILEPOS(next)-pos;
endpos = pos+compressed;
if (compressed<=BUFFERSIZE)
{
if (bufferstart<=pos
&& bufferend>= 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);
}