/*
======================
=
= 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);
}