/************************************************************************************
// File streaming code...
// Needs some lib functions to be un-staticced, sadly....

static void fileCDDATgetLocation(char *fName, long *sector, long *length)
static char FILEIO_PCROOT[64];
static TextureBankType *texBank[MAXTEXBANKS];

Consequently, not linked into the project yet, until either Andy S does the relevant thang,
Or until I remove IslFile from the libs, and stick it into the project instead.

************************************************************************************/
#include "global.h"	// actually, we just need enough to get sound.h working
#include "sptstream.h"
#include "sound.h"

// We can't link into the texbanks until IslTex has a static redefined
// (okay, it has been)
#define LINK_INTO_TEXBANKS

// Set if we're loading from the PC in the game, but need the CD loaders in this file
//#define STREAMTEST_FROM_CD


#if GOLDCD==1
  #define STREAM_PC NO
  #undef STREAMTEST_FROM_CD
#else
  #ifdef STREAMTEST_FROM_CD
    #define STREAM_PC NO
  #else
    #define STREAM_PC YES
  #endif
#endif


// JS : The following includes should be in global.h
/*#include <sys/types.h>
#include <libcd.h>
#include <libsn.h>
#include <stdio.h>
#include <string.h>
#include <islmem.h>
#include <islutil.h>
#include <islfile.h>*/
#include "global.h"
#include "maths.h"

extern unsigned short textureAddCLUT256(unsigned short *palette);


/* CD READING CODE *********************************************************************************/

// These routines should only be compiled if we want to test the CD streaming while ISLFILE is still
// set to load from the PC side of things.


//static char FILEIO_PCROOT[64];	//	"C:\\PSX\\MYGAME\\CD\\"

#ifdef STREAMTEST_FROM_CD

static char FILEIO_CDINDEX[64] = "\\CRTEST.DAT;1"; //	"\\MYGAME.DAT;1"
char streamtest_initialised = 0;

typedef struct _FileIODataType
{
	int				DATsector;
	unsigned char	*index;
	unsigned char	CDresult[8];
	char			bkgFilename[256];
	int				bkgLoading;
	unsigned char	*bkgBuffer;
} FileIODataType;


extern FileIODataType	fileIO;
#endif


#ifdef STREAMTEST_FROM_CD
static int fileCDreadIndex(char *fName)
{
	CdlFILE	fp;

	if (CdSearchFile(&fp, fName)==NULL)									// Find file location
	{
		printf("Reading CD index: CdSearchFile() error\n");
		return 1;
	}
	fileIO.DATsector = CdPosToInt(&fp.pos);
	if (CdReadFile(fName, (unsigned long *)fileIO.index, 8*2048)==0)			// Read file
	{
		printf("Reading CD index: CdReadFile() error\n");
		return 2;
	}
	if (CdReadSync(0, fileIO.CDresult))										// Wait for read
	{
		printf("Reading CD index: Read error\n");
		return 3;
	}
	return 0;
}
#endif


#ifdef STREAMTEST_FROM_CD
static void fileCDInitialise(char *fileSystem)
{
	strcpy(FILEIO_CDINDEX, fileSystem);
	CdInit();

	fileIO.index = MALLOC(8*2048);

	while(fileCDreadIndex(FILEIO_CDINDEX))
	{
		printf("Problem reading CD index - retry\n");
	}

	printf("Read CD index\n");
}
#endif

#ifdef STREAMTEST_FROM_CD
void streamInitialise(char *cd)
{
	fileCDInitialise(cd);
	streamtest_initialised = 1;
}
#endif

#ifdef STREAMTEST_FROM_CD

static void fileCDDATgetLocation(char *fName, long *sector, long *length)
{
	long	crc, *iPtr;
	char	name[40];
	int		loop;

	strcpy(name, fName);
	utilUpperStr(name);
	crc = utilStr2CRC(name);
	iPtr = (long *)fileIO.index;
	loop = iPtr[1];
	iPtr += 2;
//	printf("Looking for '%s' (0x%x) %d files\n", name, crc, loop);
	while(loop>0)
	{
		if (iPtr[0]==crc)
		{
			*sector = iPtr[1]+fileIO.DATsector+8;
			*length = iPtr[2];
//			printf("Found file %d [%d]\n", *sector, *length);
			return;
		}
		iPtr += 3;
		loop--;
	}
	*sector = *length = -1;
	printf("'%s' not found in DAT file\n", fName);
}
#endif







// =====================================================================================================
// Stuff for streaming SPT files in a sector at a time...
// It's assumed that this rou is sent sectors in the correct order. No duplicates. No skips

// Prob with spt files - no initial count of number of sprites...


#define VRAM_STARTX			512
#define VRAM_PAGECOLS		8
#define VRAM_PAGEROWS		2
#define VRAM_PAGES			16
#define VRAM_PAGEW			32
#define VRAM_PAGEH			32
#define VRAM_SETX(X)		(X)
#define VRAM_SETY(Y)		((Y)*VRAM_PAGEW)
#define VRAM_SETXY(X,Y)		((X)+((Y)*VRAM_PAGEW))
#define VRAM_SETPAGE(P)		((P)<<16)
#define VRAM_GETX(HND)		((HND) & (VRAM_PAGEW-1))
#define VRAM_GETY(HND)		(((HND)/VRAM_PAGEW) & (VRAM_PAGEW-1))
#define VRAM_GETXY(HND)		((HND) & 0xffff)
#define VRAM_GETPAGE(HND)	((HND)>>16)
#define VRAM_CALCVRAMX(HND)	(512+((VRAM_GETPAGE(HND)%(VRAM_PAGECOLS))*64)+(VRAM_GETX(HND)*2))
#define VRAM_CALCVRAMY(HND)	(((VRAM_GETPAGE(HND)/(VRAM_PAGECOLS))*256)+(VRAM_GETY(HND)*8))


// Storage for the last ickle bit of sprite that OV's to the next sector
unsigned char *sptStoreBuffer;

#define SPTSTORE_READING_HEADERS 0
#define SPTSTORE_READING_SPRITES 1
#define SPTSTORE_FINISHED 2
int sptstream_doing;
int sptstream_offset;



#ifdef LINK_INTO_TEXBANKS
	#define MAXTEXBANKS			50
	extern TextureBankType *texBank[MAXTEXBANKS];
#endif

int sptstream_n_tms;
int sptstream_max_tms;

TextureType *sptstream_textures;
NSPRITE *sptstream_nsprites;

int spt_pals_grabbed;
int spt_sprs_grabbed;

// Create the main-ram buffers, ready for loading the streamed sprites into
// (Of course, the whole point of this exercise is that we DONT need a main ram buffer
// for the SPRITE or PALETTE data itself)
TextureBankType * streamLoadSptCreate(int n_tms)
{
	int mallocSize;
	TextureBankType *newBank;

	sptstream_nsprites = MALLOC(n_tms * sizeof(NSPRITE));
//	sptstream_textures = MALLOC(n_tms * sizeof(TextureType));
	sptstream_max_tms = n_tms;

	mallocSize = (sizeof(TextureBankType)) + (n_tms*4+((n_tms+7)/8)) + (sizeof(TextureType)*n_tms);
	newBank = MALLOC(mallocSize);

	newBank->numTextures = n_tms;	// it'll be corrected downwards at the end

	newBank->CRC = (unsigned long *)((unsigned char *)newBank + (sizeof(TextureBankType)));
	newBank->pNSprite = sptstream_nsprites;

	newBank->texture = (TextureType *)((unsigned char *)newBank->CRC+newBank->numTextures*4);
	memset(newBank->texture, 0, sizeof(TextureType)*newBank->numTextures);
	
	newBank->used = (unsigned char *)((unsigned char *)newBank->texture + newBank->numTextures*sizeof(TextureType));
	memset(newBank->used, 0, ((newBank->numTextures+7)/8));

	sptstream_textures = newBank->texture;
	return newBank;
}

// Startup routine called from the stream-filer.
// We basically need a two-sector-long buffer for streaming into
// If a sector finished with half a sprite, we'll copy the unfinished data to the
// start of the buffer, & load the next sector to the very next address.
unsigned char *streamLoadSptInit(int len)
{
	sptstream_n_tms = 0;
	sptstream_doing = SPTSTORE_READING_HEADERS;
	sptstream_offset = 0;
	spt_pals_grabbed = 0;
	spt_sprs_grabbed = 0;

	sptStoreBuffer = MALLOC(2048 * 2);
	return sptStoreBuffer;
}


// Tidy up the main ram texture structures, and link it into the library's bank list.

int streamLoadSptTidy(TextureBankType *newBank)
{
	int loop;
#ifdef LINK_INTO_TEXBANKS

	for(loop=0; loop<MAXTEXBANKS; loop++)
	{
		if (texBank[loop]==NULL)
		{
			texBank[loop] = newBank;
			break;
		}
	}
	if (loop==MAXTEXBANKS)
		printf("**** WARNING: OUT OF TEXTURE BANKS\n");
#endif

//	utilPrintf("n_tms = %d\n",sptstream_n_tms);

	newBank->numTextures = sptstream_n_tms;	// Write in the ACTUAL number of sprites rather than the maximum

	for(loop=0; loop<newBank->numTextures; loop++)
	{
		newBank->CRC[loop] = newBank->pNSprite[loop].crc;
	}

//	printf("marking %d spritebytes as used\n",((newBank->numTextures+7)/8));
	memset(newBank->used, 0xff, ((newBank->numTextures+7)/8));

// Free up our 2-sector buffer, and the NSPRITE transfer space.
	FREE(sptStoreBuffer);
	FREE(sptstream_nsprites);
	newBank->pNSprite = NULL;	// coz it points to sptstream_nsprites!
	return 1;
}






// Do a VRAM malloc starting at the bottom-right, so we can see how much we've got used by the streamer
extern unsigned char	VRAMblock[VRAM_PAGES][VRAM_PAGEW*VRAM_PAGEH];
int textureReverseVRAMalloc(short w, short h)
{
	int		page, x,y, xx,yy;
	unsigned char	found;

	for(page = VRAM_PAGES-1; page >= 0; page --)
	{
		for(y = VRAM_PAGEH - h; y >=0 ; y --)
		{
			for(x = VRAM_PAGEW - w; x >= 0 ; x --)
			{
				if (VRAMblock[page][VRAM_SETXY(x, y)] == 0)
				{
					found = 0;
					for(yy = y; yy < y + h; yy ++)
					{
						for(xx = x; xx < x + w; xx ++)
						{
							found |= (VRAMblock[page][VRAM_SETXY(xx, yy)]);
						}
					}
					if (!found)
					{
						for(yy = y; yy < y + h; yy ++)
						{
							for(xx = x; xx < x + w; xx ++)
							{
								VRAMblock[page][VRAM_SETXY(xx, yy)] = 1;
							}
						}
//						printf("Allocated %dx%d, from page %d @ %d,%d\n", w,h,page,x,y);
						return (VRAM_SETPAGE(page) | VRAM_SETXY(x, y));
					}
				}
			}
		}
	}
	printf("VRAM alloc FAILED!\n");
	return NULL;
}





// Note - this routine needs to run in under 1/300 of a second, because that's how frequently the CD drive will be
// sending it new sectors. Well, actually the streaming code can cope with over-runs, but they make it chug a little.

unsigned char * streamLoadSptCycle(unsigned char *sptWhereToGrabTo)
{
	static int spt_store;
	int offset_now;
	unsigned char *buffer_top;
	int ok_to_copy;
	int leave_routine;

	unsigned char *work_ptr;

	work_ptr = &sptStoreBuffer[0];

#define src_nsprite ((NSPRITE *)(work_ptr))
#define file_offset ( (int)(work_ptr - &sptStoreBuffer[0]) + (sptstream_offset))

	buffer_top = (sptWhereToGrabTo + 2048);

// If we're reading headers, copy 'em over
	if(sptstream_doing == SPTSTORE_READING_HEADERS)
	{
		while(((int)(&(src_nsprite[1])) <= (int)buffer_top) && (sptstream_doing == SPTSTORE_READING_HEADERS))
		{
			if(sptstream_n_tms < sptstream_max_tms)
			{
// okay, the header is all available
				if(src_nsprite->flags & NLASTSPR)
				{
					sptstream_doing = SPTSTORE_READING_SPRITES;
				}
				FMEMCPY(&sptstream_nsprites[sptstream_n_tms],src_nsprite,sizeof(NSPRITE));

	//			printf("img offset %d, pal offset %d\n",sptstream_nsprites[sptstream_n_tms].image,sptstream_nsprites[sptstream_n_tms].pal);

				sptstream_n_tms++;

/*
				if(sptstream_doing == SPTSTORE_READING_SPRITES)
				{
					int i;
					for(i = 0; i < sptstream_n_tms; i++)
					{
						utilPrintf(" spr %d: img = %d, pal = %d\n",i,(int)sptstream_nsprites[i].image,(int)sptstream_nsprites[i].pal);
					}
				}
*/
			}
			else
			{
				utilPrintf("Too Many Streamed Textures (%d)\n",sptstream_n_tms);
			}
			src_nsprite++;
		}
	}

// If we're not reading headers, read sprites

	leave_routine = 0;
	while((sptstream_doing == SPTSTORE_READING_SPRITES) && (!leave_routine))
	{
		int i;

// What is this - a palette? a sprite? Which sprite's it for...?
// Also, how big is it?
		for(i = 0; i < sptstream_n_tms; i++)
		{
			if(file_offset == (int)sptstream_nsprites[i].image)
			{
				int imageLength;


				TextureType *txPtr = &sptstream_textures[i];


#define nspr (&sptstream_nsprites[i])

				imageLength = (nspr->w+3)/4;


				if(nspr->flags & NEIGHTBIT)
					imageLength *= 2;
				imageLength = (imageLength * nspr->h) * 2;


				if(imageLength > 2048)
				{
					DB("Image length is > 2048\n");
					return 0;
				}
				else
				{
					imageLength+=4;	// for whatever reason, doschop always adds the extra word, even when the spr is an exact number of words long
					imageLength = (imageLength+3) & (~3);
				}

//				DB("offset %d = image data. length = %d\n",file_offset, imageLength);

// Have we got all the data for it?
				if((int)work_ptr + imageLength <= (int)buffer_top)
				{
#ifndef _WINDOWS
					RECT	rect;
#else
					RECTPS rect;
#endif
					unsigned short	ww,hh,uMax,vMax;
					int				handle;

//					DB("ok for upload\n");

					txPtr->imageCRC = 0;	// set image CRC to zero for this texture (actually, sod the image crc stuff)
					txPtr->flags = nspr->flags;
					txPtr->refCount = 1;

					ww = (nspr->w+7)/8;
					hh = (nspr->h+7)/8;

					if(nspr->flags & NEIGHTBIT)
						ww*=2;

					handle = textureReverseVRAMalloc(ww,hh);	//textureVRAMalloc(ww,hh);
					rect.x = VRAM_CALCVRAMX(handle);
					rect.y = VRAM_CALCVRAMY(handle);
					rect.w = (nspr->w+3)/4;
					rect.h = nspr->h;

					if(nspr->flags & NEIGHTBIT)
						rect.w *= 2;	

#ifdef _WINDOWS
					LoadImagePS(&rect,((unsigned long*)work_ptr)+1);
#else
					LoadImage(&rect,((unsigned long*)work_ptr)+1);
#endif
					
					txPtr->tpage = getTPage(
						((nspr->flags & NEIGHTBIT) ? 1 : 0),
						0, rect.x, rect.y);

					txPtr->x = VRAM_GETX(handle)*8;

					if(nspr->flags & NEIGHTBIT)
						txPtr->x = txPtr->x / 2;

					txPtr->y = rect.y;

					uMax = txPtr->x + nspr->w - 1;
					if (uMax > 255)
						uMax = 255;
					vMax = txPtr->y + nspr->h - 1;
					if (vMax > 255)
						vMax = 255;

					txPtr->w = nspr->w;
					txPtr->h = nspr->h;
   					txPtr->u0 = txPtr->x;
   					txPtr->v0 = txPtr->y;
   					txPtr->u1 = uMax;
   					txPtr->v1 = txPtr->y;
   					txPtr->u2 = txPtr->x;
   					txPtr->v2 = vMax;
   					txPtr->u3 = uMax;
   					txPtr->v3 = vMax;
					txPtr->handle = handle;

					spt_sprs_grabbed++;
					if(spt_sprs_grabbed == sptstream_n_tms && spt_pals_grabbed == sptstream_n_tms)
					{
						sptstream_doing = SPTSTORE_FINISHED;
					}
					work_ptr += imageLength;

//					DB("new file offset = %d\n",file_offset);
				}
				else
				{
					leave_routine = 1;	// leave this sprite till the next loop
				}
				break;	// skip out of the "i" tmap scanning loop
			}
			else if(file_offset == (int)sptstream_nsprites[i].pal)
			{
				int memsize;

//				DB("offset %d = palette data\n",file_offset);

// ignoring 256-colour for now...
// (And not bothering to check for duplicates - It'll get allocated a new palette every time)
				if(nspr->flags & NEIGHTBIT)
				{
					memsize = 256 * 2;
				}
				else
				{
					memsize = 16 * 2;
				}
				if((int)work_ptr + memsize <= (int)buffer_top)
				{
					if(nspr->flags & NEIGHTBIT)
					{
						sptstream_textures[i].clut = textureAddCLUT256((unsigned short *)work_ptr);	// blimey... Wonder how long that'll take
					}
					else
					{
						sptstream_textures[i].clut = textureAddCLUT16((unsigned short *)work_ptr);	// blimey... Wonder how long that'll take
					}
					work_ptr += memsize;
					spt_pals_grabbed++;
					if(spt_sprs_grabbed == sptstream_n_tms && spt_pals_grabbed == sptstream_n_tms)
					{
						sptstream_doing = SPTSTORE_FINISHED;
					}
				}
				else
				{
					leave_routine = 1;	// leave this palette till the next loop
				}

				break;	// skip out of the "i" tmap scanning loop
			}
		}
		if(i == sptstream_n_tms)
		{
			utilPrintf("Couldn't find sprite/pal in the streamer (%d sprites)\n",sptstream_n_tms);
			return 0;
		}

	}


// Okay, we've grabbed all we can. Copy the remainder to the bottom of the buffer, and tell the CD reader where
// we want the next sector copying to

	if(sptstream_doing != SPTSTORE_FINISHED)
	{
// Don't do any memory shuffling if we're still dma'ing out of the buffer!
		if(sptstream_doing != SPTSTORE_READING_HEADERS)
			DrawSync(0);

// up the offset pointer by however much we managed to read out of the file
		sptstream_offset += (work_ptr - &sptStoreBuffer[0]);

		if((int)work_ptr < (int)buffer_top)
		{
			FMEMCPY(&sptStoreBuffer[0],work_ptr, ((int)buffer_top - (int)work_ptr));
		}

		sptWhereToGrabTo = &sptStoreBuffer[0] + ((int)buffer_top - (int)work_ptr);
	}
	return sptWhereToGrabTo;
}




// Simple routines for transferring a file to memory, using the streaming technology.
// (ie, not the sprite stuff)
typedef unsigned char *( *STREAM_START_ROU)(int);
typedef unsigned char *( *STREAM_CYCLE_ROU)(unsigned char *);

unsigned char *streamLoadStart(int len)
{
	return MALLOC((len + 2047) & ~2047);
}
unsigned char *streamLoadCycle(unsigned char *src)
{
	return(src + 2048);
}





// Test the spt streamer without the CD code...
// (By loading the file to main ram, & feeding it a bit at a time to the streamer code)

void TESTdelay(int n)
{
	int temp;
	while(n)
	{
		utilPrintf("delay...\n");

		temp = VSync(1);
		while(temp == VSync(1));
		n--;
	}
}







#if STREAM_PC==NO

// Try to start reading from the CD at the given point.
// This routine should be repeatedly called until it gives in.
int TESTtrySeek(CdlLOC *pos)
{
	u_char param[4];
	unsigned char	CDresult[8];
/*
Returned contents of the result's "status" byte
	CdlStatPlay			0x80 1: CD-DA playing
	CdlStatSeek			0x40 1: seeking
	CdlStatRead			0x20 1: reading data sector
	CdlStatShellOpen	0x10 1: shell open*
	CdlStatSeekError	0x04 1: error during seeking/reading
	CdlStatStandby		0x02 1: motor rotating
	CdlStatError		0x01 1: command issue error
IslFile has "equal to zero" as being the error condition
I'll just check for "error, shell open, not spinning".
&02,&22,&42 are returns we get under quite normal circumstances
*/

// Ask for 2340-long sectors, not 2048. Specifically, we want the 12 bytes at the start which are the sector number,
// which we're gonna use for error / skipping / taking-too-long detection
	param[0] = (CdlModeSpeed|CdlModeSize1);
	if(CdControl(CdlSetmode, param, &CDresult[0]) == 0)
		return 0;

	if(CDresult[0] & 0x11 || !(CDresult[0] & 0x02))	// &02 is the normal result
	{
		utilPrintf("CD result %2x\n",(int)CDresult[0]);
		return 0;
	}

	if(CdControl(CdlReadN, (u_char *)pos, &CDresult[0]) == 0)	// "ReadN" retrys on data errors
		return 0;

	if(CDresult[0] & 0x11 || !(CDresult[0] & 0x02))	// &22 or &42 are the normal results
	{
		utilPrintf("CD result %2x\n",(int)CDresult[0]);
		return 0;
	}

	return 1;
}

// Streaming a file in from the PSX CD, in 2048-byte chunks...
// Copes with high delays in processing the streamed data, and with the drawer being opened, etc, etc
unsigned char *streamLoad2(unsigned char *fName, int *length, STREAM_START_ROU startrou, STREAM_CYCLE_ROU cyclerou)
{
	long	sec_base;
	long	sec_rqd;
	long len;
	CdlLOC pos;
	int secs_left;
	unsigned char *base_addr;
	unsigned char *work_addr;
	int seek_rqd = 1;

#ifdef STREAMTEST_FROM_CD
	if(!streamtest_initialised)
	{
		streamInitialise("\\CRTEST.DAT;1");
	}
#endif

	printf("Stream-Loading %s from CD...\n",fName);

	fileCDDATgetLocation(fName, &sec_base, &len);
	if (sec_base == -1)
		return 0;
	secs_left = (len + 2047) >> 11;
	base_addr = startrou(len);

	work_addr = base_addr;
	sec_rqd = sec_base;


	while(secs_left)
	{
		int sec_got;
		CdlLOC addr_got;

// If we need to seek to the required sector
// (either because we had an unexpected sector, or because we just started)
// do it now
		if(seek_rqd)
		{
			seek_rqd = 0;

			utilPrintf("Seek Required\n");

			CdIntToPos(sec_rqd, &pos);

			while(!TESTtrySeek(&pos))
			{
				utilPrintf("Seek failed. Retry\n");
			}
		}

		if (CdReady(0, 0) != CdlDataReady)	// "wait for ready"(0,0) returns "ready" or "error". "not ready" never happens
		{
			seek_rqd = 1;
		}


		if(!seek_rqd)
		{

// Check that we've got the sector that we're expecting
// the three extra "location" longs are what "CdlModeSize1" gives us
			CdGetSector(&addr_got,3);
			CdDataSync(0);
			sec_got = CdPosToInt(&addr_got);

			if(sec_got == sec_rqd)
			{
// We've got the right sector
//				utilPrintf("rqd sec %d, got sec %d\n",sec_rqd,sec_got);

				CdGetSector(work_addr, 2048/4);
				CdDataSync(0);

				secs_left--;
				sec_rqd++;

				work_addr = cyclerou(work_addr);	// okay. Now this can overrun, timewise, so be careful



/*
				if(secs_left == 5)	// Artificial error-introducer
				{
					TESTdelay(10);
				}
*/

			}
			else
			{
// The sector we've got isn't the one we want (either because of errors, delays, or whatever...)
// Go back to the sector that we want.
				utilPrintf("*** Wrong Sector: rqd sec %d, got sec %d ***\n",sec_rqd,sec_got);
				seek_rqd = 1;
			}
		}


	}

// Return to 2048-byte sectors...
// (remove the "|CdlModeSize1")
	{
		u_char param[4];
		param[0] = (CdlModeSpeed);
		while(CdControl(CdlSetmode, param, 0) == 0)
		{
			utilPrintf("resetting sector length failed\n");
			return 0;
		}
	}


	utilPrintf("Done.\n");
	return base_addr;
}


#endif


// Initialisation of the Streaming stuff...



#if STREAM_PC==YES

// Streaming a file in from the PC, in 2048-byte chunks...
unsigned char *streamLoad2(unsigned char *fName, int *length, STREAM_START_ROU startrou, STREAM_CYCLE_ROU cyclerou)
{
	long	fHandle, size;
	unsigned char	*buffer;
	char	pathName[256], *ptr;
	unsigned char *base_addr;
	unsigned char *work_addr;
	int secs_left;


	printf("Stream-Loading %s from PC Drive...\n",fName);

#ifndef _WINDOWS
	strcpy(pathName, FILEIO_PCROOT);
#else
	strcpy(pathName, PC_FILEIO_ROOT);	
#endif

	strcat(pathName, fName);
	if ((fHandle = PCopen(pathName, 0,0))==-1)
	{
		printf("Error opening PC file '%s'\n", pathName);
		return NULL;
	}
	size = PClseek(fHandle, 0,2);

	if(length)
		*length = size;

	PClseek(fHandle, 0,0);

	base_addr = startrou(size);
	secs_left = (size + 2047) >> 11;

	work_addr = base_addr;
	while(secs_left)
	{
//		utilPrintf("PC stream %d\n",secs_left);
		secs_left--;
		if(secs_left == 0)
			PCread(fHandle, work_addr, size & 2047);
		else
			PCread(fHandle, work_addr, 2048);

		work_addr = cyclerou(work_addr);


		if(!work_addr)
		{
			DB("PC Stream failure\n");
			PCclose(fHandle);
			CRASH;
		}

	}
	PCclose(fHandle);
	return base_addr;
}

#endif




// Test routine that just loads a file into memory using the streamer
// (Can't cope with compression)
unsigned char *streamLoad(unsigned char *fName, int *length)
{
	return(streamLoad2(fName,length,streamLoadStart,streamLoadCycle));
}

// The real deal. Load a SPT file in through a little keyhole...

TextureBankType *streamLoadSpt(char *fName, int n_tms)
{
	unsigned char *addr;
	int len;
	int pos;
	unsigned int t;
	unsigned char *target;
	TextureBankType *newBank;

	sound_XA_PauseForLoading();

#ifndef _WINDOWS
	newBank = streamLoadSptCreate(n_tms);

	if(!streamLoad2(fName,&len,streamLoadSptInit,streamLoadSptCycle))
		return 0;
	if(!streamLoadSptTidy(newBank))
		return 0;
#else
	newBank = textureLoadBank(fName);
#endif

	sound_XA_Resume(-1);

	return newBank;
}

