wolf3d

The original open source release of Wolfenstein 3D
Log | Files | Refs

ID_CA.C (31762B)


      1 // ID_CA.C
      2 
      3 // this has been customized for WOLF
      4 
      5 /*
      6 =============================================================================
      7 
      8 Id Software Caching Manager
      9 ---------------------------
     10 
     11 Must be started BEFORE the memory manager, because it needs to get the headers
     12 loaded into the data segment
     13 
     14 =============================================================================
     15 */
     16 
     17 #include "ID_HEADS.H"
     18 #pragma hdrstop
     19 
     20 #pragma warn -pro
     21 #pragma warn -use
     22 
     23 #define THREEBYTEGRSTARTS
     24 
     25 /*
     26 =============================================================================
     27 
     28 						 LOCAL CONSTANTS
     29 
     30 =============================================================================
     31 */
     32 
     33 typedef struct
     34 {
     35   unsigned bit0,bit1;	// 0-255 is a character, > is a pointer to a node
     36 } huffnode;
     37 
     38 
     39 typedef struct
     40 {
     41 	unsigned	RLEWtag;
     42 	long		headeroffsets[100];
     43 	byte		tileinfo[];
     44 } mapfiletype;
     45 
     46 
     47 /*
     48 =============================================================================
     49 
     50 						 GLOBAL VARIABLES
     51 
     52 =============================================================================
     53 */
     54 
     55 byte 		_seg	*tinf;
     56 int			mapon;
     57 
     58 unsigned	_seg	*mapsegs[MAPPLANES];
     59 maptype		_seg	*mapheaderseg[NUMMAPS];
     60 byte		_seg	*audiosegs[NUMSNDCHUNKS];
     61 void		_seg	*grsegs[NUMCHUNKS];
     62 
     63 byte		far	grneeded[NUMCHUNKS];
     64 byte		ca_levelbit,ca_levelnum;
     65 
     66 int			profilehandle,debughandle;
     67 
     68 char		audioname[13]="AUDIO.";
     69 
     70 /*
     71 =============================================================================
     72 
     73 						 LOCAL VARIABLES
     74 
     75 =============================================================================
     76 */
     77 
     78 extern	long	far	CGAhead;
     79 extern	long	far	EGAhead;
     80 extern	byte	CGAdict;
     81 extern	byte	EGAdict;
     82 extern	byte	far	maphead;
     83 extern	byte	mapdict;
     84 extern	byte	far	audiohead;
     85 extern	byte	audiodict;
     86 
     87 
     88 char extension[5],	// Need a string, not constant to change cache files
     89      gheadname[10]=GREXT"HEAD.",
     90      gfilename[10]=GREXT"GRAPH.",
     91      gdictname[10]=GREXT"DICT.",
     92      mheadname[10]="MAPHEAD.",
     93      mfilename[10]="MAPTEMP.",
     94      aheadname[10]="AUDIOHED.",
     95      afilename[10]="AUDIOT.";
     96 
     97 void CA_CannotOpen(char *string);
     98 
     99 long		_seg *grstarts;	// array of offsets in egagraph, -1 for sparse
    100 long		_seg *audiostarts;	// array of offsets in audio / audiot
    101 
    102 #ifdef GRHEADERLINKED
    103 huffnode	*grhuffman;
    104 #else
    105 huffnode	grhuffman[255];
    106 #endif
    107 
    108 #ifdef AUDIOHEADERLINKED
    109 huffnode	*audiohuffman;
    110 #else
    111 huffnode	audiohuffman[255];
    112 #endif
    113 
    114 
    115 int			grhandle;		// handle to EGAGRAPH
    116 int			maphandle;		// handle to MAPTEMP / GAMEMAPS
    117 int			audiohandle;	// handle to AUDIOT / AUDIO
    118 
    119 long		chunkcomplen,chunkexplen;
    120 
    121 SDMode		oldsoundmode;
    122 
    123 
    124 
    125 void	CAL_CarmackExpand (unsigned far *source, unsigned far *dest,
    126 		unsigned length);
    127 
    128 
    129 #ifdef THREEBYTEGRSTARTS
    130 #define FILEPOSSIZE	3
    131 //#define	GRFILEPOS(c) (*(long far *)(((byte far *)grstarts)+(c)*3)&0xffffff)
    132 long GRFILEPOS(int c)
    133 {
    134 	long value;
    135 	int	offset;
    136 
    137 	offset = c*3;
    138 
    139 	value = *(long far *)(((byte far *)grstarts)+offset);
    140 
    141 	value &= 0x00ffffffl;
    142 
    143 	if (value == 0xffffffl)
    144 		value = -1;
    145 
    146 	return value;
    147 };
    148 #else
    149 #define FILEPOSSIZE	4
    150 #define	GRFILEPOS(c) (grstarts[c])
    151 #endif
    152 
    153 /*
    154 =============================================================================
    155 
    156 					   LOW LEVEL ROUTINES
    157 
    158 =============================================================================
    159 */
    160 
    161 /*
    162 ============================
    163 =
    164 = CA_OpenDebug / CA_CloseDebug
    165 =
    166 = Opens a binary file with the handle "debughandle"
    167 =
    168 ============================
    169 */
    170 
    171 void CA_OpenDebug (void)
    172 {
    173 	unlink ("DEBUG.TXT");
    174 	debughandle = open("DEBUG.TXT", O_CREAT | O_WRONLY | O_TEXT);
    175 }
    176 
    177 void CA_CloseDebug (void)
    178 {
    179 	close (debughandle);
    180 }
    181 
    182 
    183 
    184 /*
    185 ============================
    186 =
    187 = CAL_GetGrChunkLength
    188 =
    189 = Gets the length of an explicit length chunk (not tiles)
    190 = The file pointer is positioned so the compressed data can be read in next.
    191 =
    192 ============================
    193 */
    194 
    195 void CAL_GetGrChunkLength (int chunk)
    196 {
    197 	lseek(grhandle,GRFILEPOS(chunk),SEEK_SET);
    198 	read(grhandle,&chunkexplen,sizeof(chunkexplen));
    199 	chunkcomplen = GRFILEPOS(chunk+1)-GRFILEPOS(chunk)-4;
    200 }
    201 
    202 
    203 /*
    204 ==========================
    205 =
    206 = CA_FarRead
    207 =
    208 = Read from a file to a far pointer
    209 =
    210 ==========================
    211 */
    212 
    213 boolean CA_FarRead (int handle, byte far *dest, long length)
    214 {
    215 	if (length>0xffffl)
    216 		Quit ("CA_FarRead doesn't support 64K reads yet!");
    217 
    218 asm		push	ds
    219 asm		mov	bx,[handle]
    220 asm		mov	cx,[WORD PTR length]
    221 asm		mov	dx,[WORD PTR dest]
    222 asm		mov	ds,[WORD PTR dest+2]
    223 asm		mov	ah,0x3f				// READ w/handle
    224 asm		int	21h
    225 asm		pop	ds
    226 asm		jnc	good
    227 	errno = _AX;
    228 	return	false;
    229 good:
    230 asm		cmp	ax,[WORD PTR length]
    231 asm		je	done
    232 	errno = EINVFMT;			// user manager knows this is bad read
    233 	return	false;
    234 done:
    235 	return	true;
    236 }
    237 
    238 
    239 /*
    240 ==========================
    241 =
    242 = CA_SegWrite
    243 =
    244 = Write from a file to a far pointer
    245 =
    246 ==========================
    247 */
    248 
    249 boolean CA_FarWrite (int handle, byte far *source, long length)
    250 {
    251 	if (length>0xffffl)
    252 		Quit ("CA_FarWrite doesn't support 64K reads yet!");
    253 
    254 asm		push	ds
    255 asm		mov	bx,[handle]
    256 asm		mov	cx,[WORD PTR length]
    257 asm		mov	dx,[WORD PTR source]
    258 asm		mov	ds,[WORD PTR source+2]
    259 asm		mov	ah,0x40			// WRITE w/handle
    260 asm		int	21h
    261 asm		pop	ds
    262 asm		jnc	good
    263 	errno = _AX;
    264 	return	false;
    265 good:
    266 asm		cmp	ax,[WORD PTR length]
    267 asm		je	done
    268 	errno = ENOMEM;				// user manager knows this is bad write
    269 	return	false;
    270 
    271 done:
    272 	return	true;
    273 }
    274 
    275 
    276 /*
    277 ==========================
    278 =
    279 = CA_ReadFile
    280 =
    281 = Reads a file into an allready allocated buffer
    282 =
    283 ==========================
    284 */
    285 
    286 boolean CA_ReadFile (char *filename, memptr *ptr)
    287 {
    288 	int handle;
    289 	long size;
    290 
    291 	if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)
    292 		return false;
    293 
    294 	size = filelength (handle);
    295 	if (!CA_FarRead (handle,*ptr,size))
    296 	{
    297 		close (handle);
    298 		return false;
    299 	}
    300 	close (handle);
    301 	return true;
    302 }
    303 
    304 
    305 /*
    306 ==========================
    307 =
    308 = CA_WriteFile
    309 =
    310 = Writes a file from a memory buffer
    311 =
    312 ==========================
    313 */
    314 
    315 boolean CA_WriteFile (char *filename, void far *ptr, long length)
    316 {
    317 	int handle;
    318 	long size;
    319 
    320 	handle = open(filename,O_CREAT | O_BINARY | O_WRONLY,
    321 				S_IREAD | S_IWRITE | S_IFREG);
    322 
    323 	if (handle == -1)
    324 		return false;
    325 
    326 	if (!CA_FarWrite (handle,ptr,length))
    327 	{
    328 		close (handle);
    329 		return false;
    330 	}
    331 	close (handle);
    332 	return true;
    333 }
    334 
    335 
    336 
    337 /*
    338 ==========================
    339 =
    340 = CA_LoadFile
    341 =
    342 = Allocate space for and load a file
    343 =
    344 ==========================
    345 */
    346 
    347 boolean CA_LoadFile (char *filename, memptr *ptr)
    348 {
    349 	int handle;
    350 	long size;
    351 
    352 	if ((handle = open(filename,O_RDONLY | O_BINARY, S_IREAD)) == -1)
    353 		return false;
    354 
    355 	size = filelength (handle);
    356 	MM_GetPtr (ptr,size);
    357 	if (!CA_FarRead (handle,*ptr,size))
    358 	{
    359 		close (handle);
    360 		return false;
    361 	}
    362 	close (handle);
    363 	return true;
    364 }
    365 
    366 /*
    367 ============================================================================
    368 
    369 		COMPRESSION routines, see JHUFF.C for more
    370 
    371 ============================================================================
    372 */
    373 
    374 
    375 
    376 /*
    377 ===============
    378 =
    379 = CAL_OptimizeNodes
    380 =
    381 = Goes through a huffman table and changes the 256-511 node numbers to the
    382 = actular address of the node.  Must be called before CAL_HuffExpand
    383 =
    384 ===============
    385 */
    386 
    387 void CAL_OptimizeNodes (huffnode *table)
    388 {
    389   huffnode *node;
    390   int i;
    391 
    392   node = table;
    393 
    394   for (i=0;i<255;i++)
    395   {
    396 	if (node->bit0 >= 256)
    397 	  node->bit0 = (unsigned)(table+(node->bit0-256));
    398 	if (node->bit1 >= 256)
    399 	  node->bit1 = (unsigned)(table+(node->bit1-256));
    400 	node++;
    401   }
    402 }
    403 
    404 
    405 
    406 /*
    407 ======================
    408 =
    409 = CAL_HuffExpand
    410 =
    411 = Length is the length of the EXPANDED data
    412 = If screenhack, the data is decompressed in four planes directly
    413 = to the screen
    414 =
    415 ======================
    416 */
    417 
    418 void CAL_HuffExpand (byte huge *source, byte huge *dest,
    419   long length,huffnode *hufftable, boolean screenhack)
    420 {
    421 //  unsigned bit,byte,node,code;
    422   unsigned sourceseg,sourceoff,destseg,destoff,endoff;
    423   huffnode *headptr;
    424   byte		mapmask;
    425 //  huffnode *nodeon;
    426 
    427   headptr = hufftable+254;	// head node is allways node 254
    428 
    429   source++;	// normalize
    430   source--;
    431   dest++;
    432   dest--;
    433 
    434   if (screenhack)
    435   {
    436 	mapmask = 1;
    437 asm	mov	dx,SC_INDEX
    438 asm	mov	ax,SC_MAPMASK + 256
    439 asm	out	dx,ax
    440 	length >>= 2;
    441   }
    442 
    443   sourceseg = FP_SEG(source);
    444   sourceoff = FP_OFF(source);
    445   destseg = FP_SEG(dest);
    446   destoff = FP_OFF(dest);
    447   endoff = destoff+length;
    448 
    449 //
    450 // ds:si source
    451 // es:di dest
    452 // ss:bx node pointer
    453 //
    454 
    455 	if (length <0xfff0)
    456 	{
    457 
    458 //--------------------------
    459 // expand less than 64k of data
    460 //--------------------------
    461 
    462 asm mov	bx,[headptr]
    463 
    464 asm	mov	si,[sourceoff]
    465 asm	mov	di,[destoff]
    466 asm	mov	es,[destseg]
    467 asm	mov	ds,[sourceseg]
    468 asm	mov	ax,[endoff]
    469 
    470 asm	mov	ch,[si]				// load first byte
    471 asm	inc	si
    472 asm	mov	cl,1
    473 
    474 expandshort:
    475 asm	test	ch,cl			// bit set?
    476 asm	jnz	bit1short
    477 asm	mov	dx,[ss:bx]			// take bit0 path from node
    478 asm	shl	cl,1				// advance to next bit position
    479 asm	jc	newbyteshort
    480 asm	jnc	sourceupshort
    481 
    482 bit1short:
    483 asm	mov	dx,[ss:bx+2]		// take bit1 path
    484 asm	shl	cl,1				// advance to next bit position
    485 asm	jnc	sourceupshort
    486 
    487 newbyteshort:
    488 asm	mov	ch,[si]				// load next byte
    489 asm	inc	si
    490 asm	mov	cl,1				// back to first bit
    491 
    492 sourceupshort:
    493 asm	or	dh,dh				// if dx<256 its a byte, else move node
    494 asm	jz	storebyteshort
    495 asm	mov	bx,dx				// next node = (huffnode *)code
    496 asm	jmp	expandshort
    497 
    498 storebyteshort:
    499 asm	mov	[es:di],dl
    500 asm	inc	di					// write a decopmpressed byte out
    501 asm	mov	bx,[headptr]		// back to the head node for next bit
    502 
    503 asm	cmp	di,ax				// done?
    504 asm	jne	expandshort
    505 
    506 //
    507 // perform screenhack if needed
    508 //
    509 asm	test	[screenhack],1
    510 asm	jz	notscreen
    511 asm	shl	[mapmask],1
    512 asm	mov	ah,[mapmask]
    513 asm	cmp	ah,16
    514 asm	je	notscreen			// all four planes done
    515 asm	mov	dx,SC_INDEX
    516 asm	mov	al,SC_MAPMASK
    517 asm	out	dx,ax
    518 asm	mov	di,[destoff]
    519 asm	mov	ax,[endoff]
    520 asm	jmp	expandshort
    521 
    522 notscreen:;
    523 	}
    524 	else
    525 	{
    526 
    527 //--------------------------
    528 // expand more than 64k of data
    529 //--------------------------
    530 
    531   length--;
    532 
    533 asm mov	bx,[headptr]
    534 asm	mov	cl,1
    535 
    536 asm	mov	si,[sourceoff]
    537 asm	mov	di,[destoff]
    538 asm	mov	es,[destseg]
    539 asm	mov	ds,[sourceseg]
    540 
    541 asm	lodsb			// load first byte
    542 
    543 expand:
    544 asm	test	al,cl		// bit set?
    545 asm	jnz	bit1
    546 asm	mov	dx,[ss:bx]	// take bit0 path from node
    547 asm	jmp	gotcode
    548 bit1:
    549 asm	mov	dx,[ss:bx+2]	// take bit1 path
    550 
    551 gotcode:
    552 asm	shl	cl,1		// advance to next bit position
    553 asm	jnc	sourceup
    554 asm	lodsb
    555 asm	cmp	si,0x10		// normalize ds:si
    556 asm  	jb	sinorm
    557 asm	mov	cx,ds
    558 asm	inc	cx
    559 asm	mov	ds,cx
    560 asm	xor	si,si
    561 sinorm:
    562 asm	mov	cl,1		// back to first bit
    563 
    564 sourceup:
    565 asm	or	dh,dh		// if dx<256 its a byte, else move node
    566 asm	jz	storebyte
    567 asm	mov	bx,dx		// next node = (huffnode *)code
    568 asm	jmp	expand
    569 
    570 storebyte:
    571 asm	mov	[es:di],dl
    572 asm	inc	di		// write a decopmpressed byte out
    573 asm	mov	bx,[headptr]	// back to the head node for next bit
    574 
    575 asm	cmp	di,0x10		// normalize es:di
    576 asm  	jb	dinorm
    577 asm	mov	dx,es
    578 asm	inc	dx
    579 asm	mov	es,dx
    580 asm	xor	di,di
    581 dinorm:
    582 
    583 asm	sub	[WORD PTR ss:length],1
    584 asm	jnc	expand
    585 asm  	dec	[WORD PTR ss:length+2]
    586 asm	jns	expand		// when length = ffff ffff, done
    587 
    588 	}
    589 
    590 asm	mov	ax,ss
    591 asm	mov	ds,ax
    592 
    593 }
    594 
    595 
    596 /*
    597 ======================
    598 =
    599 = CAL_CarmackExpand
    600 =
    601 = Length is the length of the EXPANDED data
    602 =
    603 ======================
    604 */
    605 
    606 #define NEARTAG	0xa7
    607 #define FARTAG	0xa8
    608 
    609 void CAL_CarmackExpand (unsigned far *source, unsigned far *dest, unsigned length)
    610 {
    611 	unsigned	ch,chhigh,count,offset;
    612 	unsigned	far *copyptr, far *inptr, far *outptr;
    613 
    614 	length/=2;
    615 
    616 	inptr = source;
    617 	outptr = dest;
    618 
    619 	while (length)
    620 	{
    621 		ch = *inptr++;
    622 		chhigh = ch>>8;
    623 		if (chhigh == NEARTAG)
    624 		{
    625 			count = ch&0xff;
    626 			if (!count)
    627 			{				// have to insert a word containing the tag byte
    628 				ch |= *((unsigned char far *)inptr)++;
    629 				*outptr++ = ch;
    630 				length--;
    631 			}
    632 			else
    633 			{
    634 				offset = *((unsigned char far *)inptr)++;
    635 				copyptr = outptr - offset;
    636 				length -= count;
    637 				while (count--)
    638 					*outptr++ = *copyptr++;
    639 			}
    640 		}
    641 		else if (chhigh == FARTAG)
    642 		{
    643 			count = ch&0xff;
    644 			if (!count)
    645 			{				// have to insert a word containing the tag byte
    646 				ch |= *((unsigned char far *)inptr)++;
    647 				*outptr++ = ch;
    648 				length --;
    649 			}
    650 			else
    651 			{
    652 				offset = *inptr++;
    653 				copyptr = dest + offset;
    654 				length -= count;
    655 				while (count--)
    656 					*outptr++ = *copyptr++;
    657 			}
    658 		}
    659 		else
    660 		{
    661 			*outptr++ = ch;
    662 			length --;
    663 		}
    664 	}
    665 }
    666 
    667 
    668 
    669 /*
    670 ======================
    671 =
    672 = CA_RLEWcompress
    673 =
    674 ======================
    675 */
    676 
    677 long CA_RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,
    678   unsigned rlewtag)
    679 {
    680   long complength;
    681   unsigned value,count,i;
    682   unsigned huge *start,huge *end;
    683 
    684   start = dest;
    685 
    686   end = source + (length+1)/2;
    687 
    688 //
    689 // compress it
    690 //
    691   do
    692   {
    693 	count = 1;
    694 	value = *source++;
    695 	while (*source == value && source<end)
    696 	{
    697 	  count++;
    698 	  source++;
    699 	}
    700 	if (count>3 || value == rlewtag)
    701 	{
    702     //
    703     // send a tag / count / value string
    704     //
    705       *dest++ = rlewtag;
    706       *dest++ = count;
    707       *dest++ = value;
    708     }
    709     else
    710     {
    711     //
    712     // send word without compressing
    713     //
    714       for (i=1;i<=count;i++)
    715 	*dest++ = value;
    716 	}
    717 
    718   } while (source<end);
    719 
    720   complength = 2*(dest-start);
    721   return complength;
    722 }
    723 
    724 
    725 /*
    726 ======================
    727 =
    728 = CA_RLEWexpand
    729 = length is EXPANDED length
    730 =
    731 ======================
    732 */
    733 
    734 void CA_RLEWexpand (unsigned huge *source, unsigned huge *dest,long length,
    735   unsigned rlewtag)
    736 {
    737 //  unsigned value,count,i;
    738   unsigned huge *end;
    739   unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
    740 
    741 
    742 //
    743 // expand it
    744 //
    745 #if 0
    746   do
    747   {
    748 	value = *source++;
    749 	if (value != rlewtag)
    750 	//
    751 	// uncompressed
    752 	//
    753 	  *dest++=value;
    754 	else
    755 	{
    756 	//
    757 	// compressed string
    758 	//
    759 	  count = *source++;
    760 	  value = *source++;
    761 	  for (i=1;i<=count;i++)
    762 	*dest++ = value;
    763 	}
    764   } while (dest<end);
    765 #endif
    766 
    767   end = dest + (length)/2;
    768   sourceseg = FP_SEG(source);
    769   sourceoff = FP_OFF(source);
    770   destseg = FP_SEG(dest);
    771   destoff = FP_OFF(dest);
    772   endseg = FP_SEG(end);
    773   endoff = FP_OFF(end);
    774 
    775 
    776 //
    777 // ax = source value
    778 // bx = tag value
    779 // cx = repeat counts
    780 // dx = scratch
    781 //
    782 // NOTE: A repeat count that produces 0xfff0 bytes can blow this!
    783 //
    784 
    785 asm	mov	bx,rlewtag
    786 asm	mov	si,sourceoff
    787 asm	mov	di,destoff
    788 asm	mov	es,destseg
    789 asm	mov	ds,sourceseg
    790 
    791 expand:
    792 asm	lodsw
    793 asm	cmp	ax,bx
    794 asm	je	repeat
    795 asm	stosw
    796 asm	jmp	next
    797 
    798 repeat:
    799 asm	lodsw
    800 asm	mov	cx,ax		// repeat count
    801 asm	lodsw			// repeat value
    802 asm	rep stosw
    803 
    804 next:
    805 
    806 asm	cmp	si,0x10		// normalize ds:si
    807 asm  	jb	sinorm
    808 asm	mov	ax,si
    809 asm	shr	ax,1
    810 asm	shr	ax,1
    811 asm	shr	ax,1
    812 asm	shr	ax,1
    813 asm	mov	dx,ds
    814 asm	add	dx,ax
    815 asm	mov	ds,dx
    816 asm	and	si,0xf
    817 sinorm:
    818 asm	cmp	di,0x10		// normalize es:di
    819 asm  	jb	dinorm
    820 asm	mov	ax,di
    821 asm	shr	ax,1
    822 asm	shr	ax,1
    823 asm	shr	ax,1
    824 asm	shr	ax,1
    825 asm	mov	dx,es
    826 asm	add	dx,ax
    827 asm	mov	es,dx
    828 asm	and	di,0xf
    829 dinorm:
    830 
    831 asm	cmp     di,ss:endoff
    832 asm	jne	expand
    833 asm	mov	ax,es
    834 asm	cmp	ax,ss:endseg
    835 asm	jb	expand
    836 
    837 asm	mov	ax,ss
    838 asm	mov	ds,ax
    839 
    840 }
    841 
    842 
    843 
    844 /*
    845 =============================================================================
    846 
    847 					 CACHE MANAGER ROUTINES
    848 
    849 =============================================================================
    850 */
    851 
    852 
    853 /*
    854 ======================
    855 =
    856 = CAL_SetupGrFile
    857 =
    858 ======================
    859 */
    860 
    861 void CAL_SetupGrFile (void)
    862 {
    863 	char fname[13];
    864 	int handle;
    865 	memptr compseg;
    866 
    867 #ifdef GRHEADERLINKED
    868 
    869 	grhuffman = (huffnode *)&EGAdict;
    870 	grstarts = (long _seg *)FP_SEG(&EGAhead);
    871 
    872 	CAL_OptimizeNodes (grhuffman);
    873 
    874 #else
    875 
    876 //
    877 // load ???dict.ext (huffman dictionary for graphics files)
    878 //
    879 
    880 	strcpy(fname,gdictname);
    881 	strcat(fname,extension);
    882 
    883 	if ((handle = open(fname,
    884 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
    885 		CA_CannotOpen(fname);
    886 
    887 	read(handle, &grhuffman, sizeof(grhuffman));
    888 	close(handle);
    889 	CAL_OptimizeNodes (grhuffman);
    890 //
    891 // load the data offsets from ???head.ext
    892 //
    893 	MM_GetPtr (&(memptr)grstarts,(NUMCHUNKS+1)*FILEPOSSIZE);
    894 
    895 	strcpy(fname,gheadname);
    896 	strcat(fname,extension);
    897 
    898 	if ((handle = open(fname,
    899 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
    900 		CA_CannotOpen(fname);
    901 
    902 	CA_FarRead(handle, (memptr)grstarts, (NUMCHUNKS+1)*FILEPOSSIZE);
    903 
    904 	close(handle);
    905 
    906 
    907 #endif
    908 
    909 //
    910 // Open the graphics file, leaving it open until the game is finished
    911 //
    912 	strcpy(fname,gfilename);
    913 	strcat(fname,extension);
    914 
    915 	grhandle = open(fname, O_RDONLY | O_BINARY);
    916 	if (grhandle == -1)
    917 		CA_CannotOpen(fname);
    918 
    919 
    920 //
    921 // load the pic and sprite headers into the arrays in the data segment
    922 //
    923 	MM_GetPtr(&(memptr)pictable,NUMPICS*sizeof(pictabletype));
    924 	CAL_GetGrChunkLength(STRUCTPIC);		// position file pointer
    925 	MM_GetPtr(&compseg,chunkcomplen);
    926 	CA_FarRead (grhandle,compseg,chunkcomplen);
    927 	CAL_HuffExpand (compseg, (byte huge *)pictable,NUMPICS*sizeof(pictabletype),grhuffman,false);
    928 	MM_FreePtr(&compseg);
    929 }
    930 
    931 //==========================================================================
    932 
    933 
    934 /*
    935 ======================
    936 =
    937 = CAL_SetupMapFile
    938 =
    939 ======================
    940 */
    941 
    942 void CAL_SetupMapFile (void)
    943 {
    944 	int	i;
    945 	int handle;
    946 	long length,pos;
    947 	char fname[13];
    948 
    949 //
    950 // load maphead.ext (offsets and tileinfo for map file)
    951 //
    952 #ifndef MAPHEADERLINKED
    953 	strcpy(fname,mheadname);
    954 	strcat(fname,extension);
    955 
    956 	if ((handle = open(fname,
    957 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
    958 		CA_CannotOpen(fname);
    959 
    960 	length = filelength(handle);
    961 	MM_GetPtr (&(memptr)tinf,length);
    962 	CA_FarRead(handle, tinf, length);
    963 	close(handle);
    964 #else
    965 
    966 	tinf = (byte _seg *)FP_SEG(&maphead);
    967 
    968 #endif
    969 
    970 //
    971 // open the data file
    972 //
    973 #ifdef CARMACIZED
    974 	strcpy(fname,"GAMEMAPS.");
    975 	strcat(fname,extension);
    976 
    977 	if ((maphandle = open(fname,
    978 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
    979 		CA_CannotOpen(fname);
    980 #else
    981 	strcpy(fname,mfilename);
    982 	strcat(fname,extension);
    983 
    984 	if ((maphandle = open(fname,
    985 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
    986 		CA_CannotOpen(fname);
    987 #endif
    988 
    989 //
    990 // load all map header
    991 //
    992 	for (i=0;i<NUMMAPS;i++)
    993 	{
    994 		pos = ((mapfiletype	_seg *)tinf)->headeroffsets[i];
    995 		if (pos<0)						// $FFFFFFFF start is a sparse map
    996 			continue;
    997 
    998 		MM_GetPtr(&(memptr)mapheaderseg[i],sizeof(maptype));
    999 		MM_SetLock(&(memptr)mapheaderseg[i],true);
   1000 		lseek(maphandle,pos,SEEK_SET);
   1001 		CA_FarRead (maphandle,(memptr)mapheaderseg[i],sizeof(maptype));
   1002 	}
   1003 
   1004 //
   1005 // allocate space for 3 64*64 planes
   1006 //
   1007 	for (i=0;i<MAPPLANES;i++)
   1008 	{
   1009 		MM_GetPtr (&(memptr)mapsegs[i],64*64*2);
   1010 		MM_SetLock (&(memptr)mapsegs[i],true);
   1011 	}
   1012 }
   1013 
   1014 
   1015 //==========================================================================
   1016 
   1017 
   1018 /*
   1019 ======================
   1020 =
   1021 = CAL_SetupAudioFile
   1022 =
   1023 ======================
   1024 */
   1025 
   1026 void CAL_SetupAudioFile (void)
   1027 {
   1028 	int handle;
   1029 	long length;
   1030 	char fname[13];
   1031 
   1032 //
   1033 // load maphead.ext (offsets and tileinfo for map file)
   1034 //
   1035 #ifndef AUDIOHEADERLINKED
   1036 	strcpy(fname,aheadname);
   1037 	strcat(fname,extension);
   1038 
   1039 	if ((handle = open(fname,
   1040 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
   1041 		CA_CannotOpen(fname);
   1042 
   1043 	length = filelength(handle);
   1044 	MM_GetPtr (&(memptr)audiostarts,length);
   1045 	CA_FarRead(handle, (byte far *)audiostarts, length);
   1046 	close(handle);
   1047 #else
   1048 	audiohuffman = (huffnode *)&audiodict;
   1049 	CAL_OptimizeNodes (audiohuffman);
   1050 	audiostarts = (long _seg *)FP_SEG(&audiohead);
   1051 #endif
   1052 
   1053 //
   1054 // open the data file
   1055 //
   1056 #ifndef AUDIOHEADERLINKED
   1057 	strcpy(fname,afilename);
   1058 	strcat(fname,extension);
   1059 
   1060 	if ((audiohandle = open(fname,
   1061 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
   1062 		CA_CannotOpen(fname);
   1063 #else
   1064 	if ((audiohandle = open("AUDIO."EXTENSION,
   1065 		 O_RDONLY | O_BINARY, S_IREAD)) == -1)
   1066 		Quit ("Can't open AUDIO."EXTENSION"!");
   1067 #endif
   1068 }
   1069 
   1070 //==========================================================================
   1071 
   1072 
   1073 /*
   1074 ======================
   1075 =
   1076 = CA_Startup
   1077 =
   1078 = Open all files and load in headers
   1079 =
   1080 ======================
   1081 */
   1082 
   1083 void CA_Startup (void)
   1084 {
   1085 #ifdef PROFILE
   1086 	unlink ("PROFILE.TXT");
   1087 	profilehandle = open("PROFILE.TXT", O_CREAT | O_WRONLY | O_TEXT);
   1088 #endif
   1089 
   1090 	CAL_SetupMapFile ();
   1091 	CAL_SetupGrFile ();
   1092 	CAL_SetupAudioFile ();
   1093 
   1094 	mapon = -1;
   1095 	ca_levelbit = 1;
   1096 	ca_levelnum = 0;
   1097 
   1098 }
   1099 
   1100 //==========================================================================
   1101 
   1102 
   1103 /*
   1104 ======================
   1105 =
   1106 = CA_Shutdown
   1107 =
   1108 = Closes all files
   1109 =
   1110 ======================
   1111 */
   1112 
   1113 void CA_Shutdown (void)
   1114 {
   1115 #ifdef PROFILE
   1116 	close (profilehandle);
   1117 #endif
   1118 
   1119 	close (maphandle);
   1120 	close (grhandle);
   1121 	close (audiohandle);
   1122 }
   1123 
   1124 //===========================================================================
   1125 
   1126 /*
   1127 ======================
   1128 =
   1129 = CA_CacheAudioChunk
   1130 =
   1131 ======================
   1132 */
   1133 
   1134 void CA_CacheAudioChunk (int chunk)
   1135 {
   1136 	long	pos,compressed;
   1137 #ifdef AUDIOHEADERLINKED
   1138 	long	expanded;
   1139 	memptr	bigbufferseg;
   1140 	byte	far *source;
   1141 #endif
   1142 
   1143 	if (audiosegs[chunk])
   1144 	{
   1145 		MM_SetPurge (&(memptr)audiosegs[chunk],0);
   1146 		return;							// allready in memory
   1147 	}
   1148 
   1149 //
   1150 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate
   1151 // a larger buffer
   1152 //
   1153 	pos = audiostarts[chunk];
   1154 	compressed = audiostarts[chunk+1]-pos;
   1155 
   1156 	lseek(audiohandle,pos,SEEK_SET);
   1157 
   1158 #ifndef AUDIOHEADERLINKED
   1159 
   1160 	MM_GetPtr (&(memptr)audiosegs[chunk],compressed);
   1161 	if (mmerror)
   1162 		return;
   1163 
   1164 	CA_FarRead(audiohandle,audiosegs[chunk],compressed);
   1165 
   1166 #else
   1167 
   1168 	if (compressed<=BUFFERSIZE)
   1169 	{
   1170 		CA_FarRead(audiohandle,bufferseg,compressed);
   1171 		source = bufferseg;
   1172 	}
   1173 	else
   1174 	{
   1175 		MM_GetPtr(&bigbufferseg,compressed);
   1176 		if (mmerror)
   1177 			return;
   1178 		MM_SetLock (&bigbufferseg,true);
   1179 		CA_FarRead(audiohandle,bigbufferseg,compressed);
   1180 		source = bigbufferseg;
   1181 	}
   1182 
   1183 	expanded = *(long far *)source;
   1184 	source += 4;			// skip over length
   1185 	MM_GetPtr (&(memptr)audiosegs[chunk],expanded);
   1186 	if (mmerror)
   1187 		goto done;
   1188 	CAL_HuffExpand (source,audiosegs[chunk],expanded,audiohuffman,false);
   1189 
   1190 done:
   1191 	if (compressed>BUFFERSIZE)
   1192 		MM_FreePtr(&bigbufferseg);
   1193 #endif
   1194 }
   1195 
   1196 //===========================================================================
   1197 
   1198 /*
   1199 ======================
   1200 =
   1201 = CA_LoadAllSounds
   1202 =
   1203 = Purges all sounds, then loads all new ones (mode switch)
   1204 =
   1205 ======================
   1206 */
   1207 
   1208 void CA_LoadAllSounds (void)
   1209 {
   1210 	unsigned	start,i;
   1211 
   1212 	switch (oldsoundmode)
   1213 	{
   1214 	case sdm_Off:
   1215 		goto cachein;
   1216 	case sdm_PC:
   1217 		start = STARTPCSOUNDS;
   1218 		break;
   1219 	case sdm_AdLib:
   1220 		start = STARTADLIBSOUNDS;
   1221 		break;
   1222 	}
   1223 
   1224 	for (i=0;i<NUMSOUNDS;i++,start++)
   1225 		if (audiosegs[start])
   1226 			MM_SetPurge (&(memptr)audiosegs[start],3);		// make purgable
   1227 
   1228 cachein:
   1229 
   1230 	switch (SoundMode)
   1231 	{
   1232 	case sdm_Off:
   1233 		return;
   1234 	case sdm_PC:
   1235 		start = STARTPCSOUNDS;
   1236 		break;
   1237 	case sdm_AdLib:
   1238 		start = STARTADLIBSOUNDS;
   1239 		break;
   1240 	}
   1241 
   1242 	for (i=0;i<NUMSOUNDS;i++,start++)
   1243 		CA_CacheAudioChunk (start);
   1244 
   1245 	oldsoundmode = SoundMode;
   1246 }
   1247 
   1248 //===========================================================================
   1249 
   1250 
   1251 /*
   1252 ======================
   1253 =
   1254 = CAL_ExpandGrChunk
   1255 =
   1256 = Does whatever is needed with a pointer to a compressed chunk
   1257 =
   1258 ======================
   1259 */
   1260 
   1261 void CAL_ExpandGrChunk (int chunk, byte far *source)
   1262 {
   1263 	long	expanded;
   1264 
   1265 
   1266 	if (chunk >= STARTTILE8 && chunk < STARTEXTERNS)
   1267 	{
   1268 	//
   1269 	// expanded sizes of tile8/16/32 are implicit
   1270 	//
   1271 
   1272 #define BLOCK		64
   1273 #define MASKBLOCK	128
   1274 
   1275 		if (chunk<STARTTILE8M)			// tile 8s are all in one chunk!
   1276 			expanded = BLOCK*NUMTILE8;
   1277 		else if (chunk<STARTTILE16)
   1278 			expanded = MASKBLOCK*NUMTILE8M;
   1279 		else if (chunk<STARTTILE16M)	// all other tiles are one/chunk
   1280 			expanded = BLOCK*4;
   1281 		else if (chunk<STARTTILE32)
   1282 			expanded = MASKBLOCK*4;
   1283 		else if (chunk<STARTTILE32M)
   1284 			expanded = BLOCK*16;
   1285 		else
   1286 			expanded = MASKBLOCK*16;
   1287 	}
   1288 	else
   1289 	{
   1290 	//
   1291 	// everything else has an explicit size longword
   1292 	//
   1293 		expanded = *(long far *)source;
   1294 		source += 4;			// skip over length
   1295 	}
   1296 
   1297 //
   1298 // allocate final space, decompress it, and free bigbuffer
   1299 // Sprites need to have shifts made and various other junk
   1300 //
   1301 	MM_GetPtr (&grsegs[chunk],expanded);
   1302 	if (mmerror)
   1303 		return;
   1304 	CAL_HuffExpand (source,grsegs[chunk],expanded,grhuffman,false);
   1305 }
   1306 
   1307 
   1308 /*
   1309 ======================
   1310 =
   1311 = CA_CacheGrChunk
   1312 =
   1313 = Makes sure a given chunk is in memory, loadiing it if needed
   1314 =
   1315 ======================
   1316 */
   1317 
   1318 void CA_CacheGrChunk (int chunk)
   1319 {
   1320 	long	pos,compressed;
   1321 	memptr	bigbufferseg;
   1322 	byte	far *source;
   1323 	int		next;
   1324 
   1325 	grneeded[chunk] |= ca_levelbit;		// make sure it doesn't get removed
   1326 	if (grsegs[chunk])
   1327 	{
   1328 		MM_SetPurge (&grsegs[chunk],0);
   1329 		return;							// allready in memory
   1330 	}
   1331 
   1332 //
   1333 // load the chunk into a buffer, either the miscbuffer if it fits, or allocate
   1334 // a larger buffer
   1335 //
   1336 	pos = GRFILEPOS(chunk);
   1337 	if (pos<0)							// $FFFFFFFF start is a sparse tile
   1338 	  return;
   1339 
   1340 	next = chunk +1;
   1341 	while (GRFILEPOS(next) == -1)		// skip past any sparse tiles
   1342 		next++;
   1343 
   1344 	compressed = GRFILEPOS(next)-pos;
   1345 
   1346 	lseek(grhandle,pos,SEEK_SET);
   1347 
   1348 	if (compressed<=BUFFERSIZE)
   1349 	{
   1350 		CA_FarRead(grhandle,bufferseg,compressed);
   1351 		source = bufferseg;
   1352 	}
   1353 	else
   1354 	{
   1355 		MM_GetPtr(&bigbufferseg,compressed);
   1356 		MM_SetLock (&bigbufferseg,true);
   1357 		CA_FarRead(grhandle,bigbufferseg,compressed);
   1358 		source = bigbufferseg;
   1359 	}
   1360 
   1361 	CAL_ExpandGrChunk (chunk,source);
   1362 
   1363 	if (compressed>BUFFERSIZE)
   1364 		MM_FreePtr(&bigbufferseg);
   1365 }
   1366 
   1367 
   1368 
   1369 //==========================================================================
   1370 
   1371 /*
   1372 ======================
   1373 =
   1374 = CA_CacheScreen
   1375 =
   1376 = Decompresses a chunk from disk straight onto the screen
   1377 =
   1378 ======================
   1379 */
   1380 
   1381 void CA_CacheScreen (int chunk)
   1382 {
   1383 	long	pos,compressed,expanded;
   1384 	memptr	bigbufferseg;
   1385 	byte	far *source;
   1386 	int		next;
   1387 
   1388 //
   1389 // load the chunk into a buffer
   1390 //
   1391 	pos = GRFILEPOS(chunk);
   1392 	next = chunk +1;
   1393 	while (GRFILEPOS(next) == -1)		// skip past any sparse tiles
   1394 		next++;
   1395 	compressed = GRFILEPOS(next)-pos;
   1396 
   1397 	lseek(grhandle,pos,SEEK_SET);
   1398 
   1399 	MM_GetPtr(&bigbufferseg,compressed);
   1400 	MM_SetLock (&bigbufferseg,true);
   1401 	CA_FarRead(grhandle,bigbufferseg,compressed);
   1402 	source = bigbufferseg;
   1403 
   1404 	expanded = *(long far *)source;
   1405 	source += 4;			// skip over length
   1406 
   1407 //
   1408 // allocate final space, decompress it, and free bigbuffer
   1409 // Sprites need to have shifts made and various other junk
   1410 //
   1411 	CAL_HuffExpand (source,MK_FP(SCREENSEG,bufferofs),expanded,grhuffman,true);
   1412 	VW_MarkUpdateBlock (0,0,319,199);
   1413 	MM_FreePtr(&bigbufferseg);
   1414 }
   1415 
   1416 //==========================================================================
   1417 
   1418 /*
   1419 ======================
   1420 =
   1421 = CA_CacheMap
   1422 =
   1423 = WOLF: This is specialized for a 64*64 map size
   1424 =
   1425 ======================
   1426 */
   1427 
   1428 void CA_CacheMap (int mapnum)
   1429 {
   1430 	long	pos,compressed;
   1431 	int		plane;
   1432 	memptr	*dest,bigbufferseg;
   1433 	unsigned	size;
   1434 	unsigned	far	*source;
   1435 #ifdef CARMACIZED
   1436 	memptr	buffer2seg;
   1437 	long	expanded;
   1438 #endif
   1439 
   1440 	mapon = mapnum;
   1441 
   1442 //
   1443 // load the planes into the allready allocated buffers
   1444 //
   1445 	size = 64*64*2;
   1446 
   1447 	for (plane = 0; plane<MAPPLANES; plane++)
   1448 	{
   1449 		pos = mapheaderseg[mapnum]->planestart[plane];
   1450 		compressed = mapheaderseg[mapnum]->planelength[plane];
   1451 
   1452 		dest = &(memptr)mapsegs[plane];
   1453 
   1454 		lseek(maphandle,pos,SEEK_SET);
   1455 		if (compressed<=BUFFERSIZE)
   1456 			source = bufferseg;
   1457 		else
   1458 		{
   1459 			MM_GetPtr(&bigbufferseg,compressed);
   1460 			MM_SetLock (&bigbufferseg,true);
   1461 			source = bigbufferseg;
   1462 		}
   1463 
   1464 		CA_FarRead(maphandle,(byte far *)source,compressed);
   1465 #ifdef CARMACIZED
   1466 		//
   1467 		// unhuffman, then unRLEW
   1468 		// The huffman'd chunk has a two byte expanded length first
   1469 		// The resulting RLEW chunk also does, even though it's not really
   1470 		// needed
   1471 		//
   1472 		expanded = *source;
   1473 		source++;
   1474 		MM_GetPtr (&buffer2seg,expanded);
   1475 		CAL_CarmackExpand (source, (unsigned far *)buffer2seg,expanded);
   1476 		CA_RLEWexpand (((unsigned far *)buffer2seg)+1,*dest,size,
   1477 		((mapfiletype _seg *)tinf)->RLEWtag);
   1478 		MM_FreePtr (&buffer2seg);
   1479 
   1480 #else
   1481 		//
   1482 		// unRLEW, skipping expanded length
   1483 		//
   1484 		CA_RLEWexpand (source+1, *dest,size,
   1485 		((mapfiletype _seg *)tinf)->RLEWtag);
   1486 #endif
   1487 
   1488 		if (compressed>BUFFERSIZE)
   1489 			MM_FreePtr(&bigbufferseg);
   1490 	}
   1491 }
   1492 
   1493 //===========================================================================
   1494 
   1495 /*
   1496 ======================
   1497 =
   1498 = CA_UpLevel
   1499 =
   1500 = Goes up a bit level in the needed lists and clears it out.
   1501 = Everything is made purgable
   1502 =
   1503 ======================
   1504 */
   1505 
   1506 void CA_UpLevel (void)
   1507 {
   1508 	int	i;
   1509 
   1510 	if (ca_levelnum==7)
   1511 		Quit ("CA_UpLevel: Up past level 7!");
   1512 
   1513 	for (i=0;i<NUMCHUNKS;i++)
   1514 		if (grsegs[i])
   1515 			MM_SetPurge (&(memptr)grsegs[i],3);
   1516 	ca_levelbit<<=1;
   1517 	ca_levelnum++;
   1518 }
   1519 
   1520 //===========================================================================
   1521 
   1522 /*
   1523 ======================
   1524 =
   1525 = CA_DownLevel
   1526 =
   1527 = Goes down a bit level in the needed lists and recaches
   1528 = everything from the lower level
   1529 =
   1530 ======================
   1531 */
   1532 
   1533 void CA_DownLevel (void)
   1534 {
   1535 	if (!ca_levelnum)
   1536 		Quit ("CA_DownLevel: Down past level 0!");
   1537 	ca_levelbit>>=1;
   1538 	ca_levelnum--;
   1539 	CA_CacheMarks();
   1540 }
   1541 
   1542 //===========================================================================
   1543 
   1544 /*
   1545 ======================
   1546 =
   1547 = CA_ClearMarks
   1548 =
   1549 = Clears out all the marks at the current level
   1550 =
   1551 ======================
   1552 */
   1553 
   1554 void CA_ClearMarks (void)
   1555 {
   1556 	int i;
   1557 
   1558 	for (i=0;i<NUMCHUNKS;i++)
   1559 		grneeded[i]&=~ca_levelbit;
   1560 }
   1561 
   1562 
   1563 //===========================================================================
   1564 
   1565 /*
   1566 ======================
   1567 =
   1568 = CA_ClearAllMarks
   1569 =
   1570 = Clears out all the marks on all the levels
   1571 =
   1572 ======================
   1573 */
   1574 
   1575 void CA_ClearAllMarks (void)
   1576 {
   1577 	_fmemset (grneeded,0,sizeof(grneeded));
   1578 	ca_levelbit = 1;
   1579 	ca_levelnum = 0;
   1580 }
   1581 
   1582 
   1583 //===========================================================================
   1584 
   1585 
   1586 /*
   1587 ======================
   1588 =
   1589 = CA_FreeGraphics
   1590 =
   1591 ======================
   1592 */
   1593 
   1594 
   1595 void CA_SetGrPurge (void)
   1596 {
   1597 	int i;
   1598 
   1599 //
   1600 // free graphics
   1601 //
   1602 	CA_ClearMarks ();
   1603 
   1604 	for (i=0;i<NUMCHUNKS;i++)
   1605 		if (grsegs[i])
   1606 			MM_SetPurge (&(memptr)grsegs[i],3);
   1607 }
   1608 
   1609 
   1610 
   1611 /*
   1612 ======================
   1613 =
   1614 = CA_SetAllPurge
   1615 =
   1616 = Make everything possible purgable
   1617 =
   1618 ======================
   1619 */
   1620 
   1621 void CA_SetAllPurge (void)
   1622 {
   1623 	int i;
   1624 
   1625 
   1626 //
   1627 // free sounds
   1628 //
   1629 	for (i=0;i<NUMSNDCHUNKS;i++)
   1630 		if (audiosegs[i])
   1631 			MM_SetPurge (&(memptr)audiosegs[i],3);
   1632 
   1633 //
   1634 // free graphics
   1635 //
   1636 	CA_SetGrPurge ();
   1637 }
   1638 
   1639 
   1640 //===========================================================================
   1641 
   1642 /*
   1643 ======================
   1644 =
   1645 = CA_CacheMarks
   1646 =
   1647 ======================
   1648 */
   1649 #define MAXEMPTYREAD	1024
   1650 
   1651 void CA_CacheMarks (void)
   1652 {
   1653 	int 	i,next,numcache;
   1654 	long	pos,endpos,nextpos,nextendpos,compressed;
   1655 	long	bufferstart,bufferend;	// file position of general buffer
   1656 	byte	far *source;
   1657 	memptr	bigbufferseg;
   1658 
   1659 	numcache = 0;
   1660 //
   1661 // go through and make everything not needed purgable
   1662 //
   1663 	for (i=0;i<NUMCHUNKS;i++)
   1664 		if (grneeded[i]&ca_levelbit)
   1665 		{
   1666 			if (grsegs[i])					// its allready in memory, make
   1667 				MM_SetPurge(&grsegs[i],0);	// sure it stays there!
   1668 			else
   1669 				numcache++;
   1670 		}
   1671 		else
   1672 		{
   1673 			if (grsegs[i])					// not needed, so make it purgeable
   1674 				MM_SetPurge(&grsegs[i],3);
   1675 		}
   1676 
   1677 	if (!numcache)			// nothing to cache!
   1678 		return;
   1679 
   1680 
   1681 //
   1682 // go through and load in anything still needed
   1683 //
   1684 	bufferstart = bufferend = 0;		// nothing good in buffer now
   1685 
   1686 	for (i=0;i<NUMCHUNKS;i++)
   1687 		if ( (grneeded[i]&ca_levelbit) && !grsegs[i])
   1688 		{
   1689 			pos = GRFILEPOS(i);
   1690 			if (pos<0)
   1691 				continue;
   1692 
   1693 			next = i +1;
   1694 			while (GRFILEPOS(next) == -1)		// skip past any sparse tiles
   1695 				next++;
   1696 
   1697 			compressed = GRFILEPOS(next)-pos;
   1698 			endpos = pos+compressed;
   1699 
   1700 			if (compressed<=BUFFERSIZE)
   1701 			{
   1702 				if (bufferstart<=pos
   1703 				&& bufferend>= endpos)
   1704 				{
   1705 				// data is allready in buffer
   1706 					source = (byte _seg *)bufferseg+(pos-bufferstart);
   1707 				}
   1708 				else
   1709 				{
   1710 				// load buffer with a new block from disk
   1711 				// try to get as many of the needed blocks in as possible
   1712 					while ( next < NUMCHUNKS )
   1713 					{
   1714 						while (next < NUMCHUNKS &&
   1715 						!(grneeded[next]&ca_levelbit && !grsegs[next]))
   1716 							next++;
   1717 						if (next == NUMCHUNKS)
   1718 							continue;
   1719 
   1720 						nextpos = GRFILEPOS(next);
   1721 						while (GRFILEPOS(++next) == -1)	// skip past any sparse tiles
   1722 							;
   1723 						nextendpos = GRFILEPOS(next);
   1724 						if (nextpos - endpos <= MAXEMPTYREAD
   1725 						&& nextendpos-pos <= BUFFERSIZE)
   1726 							endpos = nextendpos;
   1727 						else
   1728 							next = NUMCHUNKS;			// read pos to posend
   1729 					}
   1730 
   1731 					lseek(grhandle,pos,SEEK_SET);
   1732 					CA_FarRead(grhandle,bufferseg,endpos-pos);
   1733 					bufferstart = pos;
   1734 					bufferend = endpos;
   1735 					source = bufferseg;
   1736 				}
   1737 			}
   1738 			else
   1739 			{
   1740 			// big chunk, allocate temporary buffer
   1741 				MM_GetPtr(&bigbufferseg,compressed);
   1742 				if (mmerror)
   1743 					return;
   1744 				MM_SetLock (&bigbufferseg,true);
   1745 				lseek(grhandle,pos,SEEK_SET);
   1746 				CA_FarRead(grhandle,bigbufferseg,compressed);
   1747 				source = bigbufferseg;
   1748 			}
   1749 
   1750 			CAL_ExpandGrChunk (i,source);
   1751 			if (mmerror)
   1752 				return;
   1753 
   1754 			if (compressed>BUFFERSIZE)
   1755 				MM_FreePtr(&bigbufferseg);
   1756 
   1757 		}
   1758 }
   1759 
   1760 void CA_CannotOpen(char *string)
   1761 {
   1762  char str[30];
   1763 
   1764  strcpy(str,"Can't open ");
   1765  strcat(str,string);
   1766  strcat(str,"!\n");
   1767  Quit (str);
   1768 }