From c4ea89ef8cb104fb6f9f9edd4f4bf55e7984a51f Mon Sep 17 00:00:00 2001 From: sparky4 Date: Thu, 2 Jul 2015 00:27:18 -0500 Subject: [PATCH] going to portover the cache system before extenting the 16_mm library! new file: src/lib/16_ca.c new file: src/lib/16_ca.h --- src/lib/16_ca.c | 2190 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib/16_ca.h | 124 +++ 2 files changed, 2314 insertions(+) create mode 100644 src/lib/16_ca.c create mode 100644 src/lib/16_ca.h diff --git a/src/lib/16_ca.c b/src/lib/16_ca.c new file mode 100644 index 00000000..bacb7181 --- /dev/null +++ b/src/lib/16_ca.c @@ -0,0 +1,2190 @@ +/* Catacomb Apocalypse 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 "ID_HEADS.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(); +} + diff --git a/src/lib/16_ca.h b/src/lib/16_ca.h new file mode 100644 index 00000000..380ae297 --- /dev/null +++ b/src/lib/16_ca.h @@ -0,0 +1,124 @@ +/* Catacomb Apocalypse 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.H + +#ifndef __TYPES__ +#include "ID_TYPES.H" +#endif + +#ifndef __ID_MM__ +#include "ID_MM.H" +#endif + +#ifndef __ID_GLOB__ +#include "ID_GLOB.H" +#endif + +#define __ID_CA__ + +//=========================================================================== + +//#define NOMAPS +//#define NOGRAPHICS +//#define NOAUDIO + +#define MAPHEADERLINKED +#define GRHEADERLINKED +#define AUDIOHEADERLINKED + +#define NUMMAPS 39 +#define MAPPLANES 3 + +//=========================================================================== + +typedef struct +{ + long planestart[3]; + unsigned planelength[3]; + unsigned width,height; + char name[16]; +} maptype; + +//=========================================================================== + +extern byte _seg *tinf; +extern int mapon; + +extern unsigned _seg *mapsegs[3]; +extern maptype _seg *mapheaderseg[NUMMAPS]; +extern byte _seg *audiosegs[NUMSNDCHUNKS]; +extern void _seg *grsegs[NUMCHUNKS]; + +extern byte far grneeded[NUMCHUNKS]; +extern byte ca_levelbit,ca_levelnum; + +extern char *titleptr[8]; + +extern int profilehandle,debughandle; + +// +// hooks for custom cache dialogs +// +extern void (*drawcachebox) (char *title, unsigned numcache); +extern void (*updatecachebox) (void); +extern void (*finishcachebox) (void); + +//=========================================================================== + +// just for the score box reshifting + +void CAL_ShiftSprite (unsigned segment,unsigned source,unsigned dest, + unsigned width, unsigned height, unsigned pixshift, boolean domask); + +//=========================================================================== + +void CA_OpenDebug (void); +void CA_CloseDebug (void); +boolean CA_FarRead (int handle, byte far *dest, long length); +boolean CA_FarWrite (int handle, byte far *source, long length); +boolean CA_ReadFile (char *filename, memptr *ptr); +boolean CA_LoadFile (char *filename, memptr *ptr); + +long CA_RLEWCompress (unsigned huge *source, long length, unsigned huge *dest, + unsigned rlewtag); + +void CA_RLEWexpand (unsigned huge *source, unsigned huge *dest,long length, + unsigned rlewtag); + +void CA_Startup (void); +void CA_Shutdown (void); + +void CA_CacheAudioChunk (int chunk); +void CA_LoadAllSounds (void); + +void CA_UpLevel (void); +void CA_DownLevel (void); + +void CA_SetAllPurge (void); + +void CA_ClearMarks (void); +void CA_ClearAllMarks (void); + +#define CA_MarkGrChunk(chunk) grneeded[chunk]|=ca_levelbit + +void CA_CacheGrChunk (int chunk); +void CA_CacheMap (int mapnum); + +void CA_CacheMarks (char *title); + -- 2.39.2