/************************************************************************************
	PSX CORE (c) 1999 ISL

	psi.c:		Playstation Model (i) Handler
************************************************************************************/

// Note - in order for this to be a drop-in replacement for the islpsi lib,
// I've got a load of islpsi routines copied in to here.


// The rendering functions in custom.c are now only used by the model viewer
// (Everything else uses custom2)


#include "global.h"

#include "bff_load.h"
#include "custom.h"
#include "timer.h"




void psiFixupMesh(PSIMESH *mesh)
{
	int p,i;


	// main pointers										
	(int)mesh->vertop = (int)mesh + (int)mesh->vertop;
	(int)mesh->nortop = (int)mesh + (int)mesh->nortop;

	(int)mesh->scalekeys = (int)mesh + (int)mesh->scalekeys;
	(int)mesh->movekeys = (int)mesh + (int)mesh->movekeys;
	(int)mesh->rotatekeys = (int)mesh + (int)mesh->rotatekeys;


// Set up our initial pointers for "last-frame" caching
#ifdef STORE_LASTFRAME
	{
		int crc;

		utilUpperStr(mesh->name);
		crc = utilStr2CRC(mesh->name);

		LASTROTATATEKEY(mesh) = 1;
		LASTSCALEKEY(mesh) = 1;
		LASTMOVEKEY(mesh) = 1;
		MESH_NAMECRC(mesh) = crc;

	//	*(ULONG *)(&mesh->name[0]) = 1;
	//	*(ULONG *)(&mesh->name[4]) = 1;
	//	*(ULONG *)(&mesh->name[8]) = 1;
	}
#endif

	// sortlist pointers
	p = (int)mesh;

	for (i=0; i<8; i++)	
		(int)mesh->sortlistptr[i] = p + (int)mesh->sortlistptr[i];

	// child and next pointers
	if (mesh->child)
	{
		(int)mesh->child = (int)mesh + (int)mesh->child;
		psiFixupMesh(mesh->child);
	}
	if (mesh->next)
	{
		(int)mesh->next = (int)mesh + (int)mesh->next;
		psiFixupMesh(mesh->next);
	}
}


void psiFixupOneRoot(PSIMESH *mesh)
{
	PSIMESH *root;

	root = mesh;

	if(!mesh->next)
		return;

	printf("One-Root PSI problem Needs Fixing\n");

	while(mesh->next)
	{
		mesh = mesh->next;
	}

	mesh->next = root->child;
	root->child = root->next;
	root->next = NULL;
}


#ifndef _WINDOWS


void customPsiCalcMaxMin(PSIDATA *psiData, long *tfd)
{
//	long *tfd = transformedDepths;
	int i;
	long localmaxDepth;
	long localminDepth;
	ULONG *sortedIndexPtr;

	sortCount=0;
	localmaxDepth = localminDepth = *tfd;
	
	// CPW: DB("start depth = %d\n", localminDepth);

	i = tfTotal;

	while (i)
	{
		if (*tfd < localminDepth)
			localminDepth = *tfd;
		if (*tfd > localmaxDepth)
			localmaxDepth = *tfd;

		tfd ++;
		i --;
	}

	maxDepth = localmaxDepth;
	minDepth = localminDepth;
	depthRange = (localmaxDepth - localminDepth) + 1;

	// CPW: DB("min = %d, max = %d\n",localminDepth,localmaxDepth);

	sortedIndexPtr = sortedIndex;
	for (i = depthRange; i != 0 ; i--)
	{
		*(sortedIndexPtr++) = 0;
	}



	if (depthRange > maxDepthRange)
	{
		printf("PROGRAM HALTED. \nDEPTH RANGE EXCEEDED !\nINCREASE MAXDEPTHRANGE TO %d (=%d)\n\n",depthRange,maxDepthRange);
// RFW: Jobe never filled in the object name anyway, and now I've altered actorCreate to use "modelName" to point to the MODEL
// (Which gives much more useful information, (absent name included)
//		printf("Object Mesh Name = >%s<\n",psiData->modelName);
		for (;;);
	}

}


#endif

// Multiply all the verts up by four...
// (note that accessing transformed normals will still need a *2)
void customPsiFixupPrims(PSIMODEL *psiModel)
{
	TextureType *sprt;
	int p,a;
	char *primitive;
	UBYTE s;

	//int ix; //temp

	p = psiModel->noofPrims;
	primitive = (char*)psiModel->primOffset;

	while (p)
	{
		
		s = ((TMD_P_GT4I*)primitive)->cd;	// code
		switch (s &(0xff-2))
		{

			case GPU_COM_G3:
			case GPU_COM_F3:	
				a = sizeof(TMD_P_FG3I );
#ifndef _WINDOWS
			 	((TMD_P_FG3I*)primitive)->v0 *= 4;
			 	((TMD_P_FG3I*)primitive)->v1 *= 4;
			 	((TMD_P_FG3I*)primitive)->v2 *= 4;
#endif
				break;

			case GPU_COM_G4:
			case GPU_COM_F4:	
				a = sizeof(TMD_P_FG4I );
#ifndef _WINDOWS
			 	((TMD_P_FG4I*)primitive)->v0 *= 4;
			 	((TMD_P_FG4I*)primitive)->v1 *= 4;
			 	((TMD_P_FG4I*)primitive)->v2 *= 4;
			 	((TMD_P_FG4I*)primitive)->v3 *= 4;
#endif
				break;

			case GPU_COM_TF3:	
				a = sizeof(TMD_P_FT3I );
#ifndef _WINDOWS
			 	((TMD_P_FT3I*)primitive)->v0 *= 4;
			 	((TMD_P_FT3I*)primitive)->v1 *= 4;
			 	((TMD_P_FT3I*)primitive)->v2 *= 4;
#endif
				break;

			case GPU_COM_TF4SPR:
			case GPU_COM_TF4:	
				a = sizeof(TMD_P_FT4I );
#ifndef _WINDOWS
			 	((TMD_P_FT4I*)primitive)->v0 *= 4;
			 	((TMD_P_FT4I*)primitive)->v1 *= 4;
			 	((TMD_P_FT4I*)primitive)->v2 *= 4;
			 	((TMD_P_FT4I*)primitive)->v3 *= 4;
#endif
				break;

			case GPU_COM_TG3:	
				a = sizeof(TMD_P_GT3I );
#ifndef _WINDOWS
			 	((TMD_P_GT3I*)primitive)->dummy &= 1;	// only use the double-sided bit
			 	((TMD_P_GT3I*)primitive)->v0 *= 4;
			 	((TMD_P_GT3I*)primitive)->v1 *= 4;
			 	((TMD_P_GT3I*)primitive)->v2 *= 4;
#endif
				break;

			case GPU_COM_TG4:	
				a = sizeof(TMD_P_GT4I );
#ifndef _WINDOWS
			 	((TMD_P_GT4I*)primitive)->dummy &= 1;	// only use the double-sided bit
			 	((TMD_P_GT4I*)primitive)->v0 *= 4;
			 	((TMD_P_GT4I*)primitive)->v1 *= 4;
			 	((TMD_P_GT4I*)primitive)->v2 *= 4;
			 	((TMD_P_GT4I*)primitive)->v3 *= 4;
#endif
				break;


			default:	
				a = 0;
				utilPrintf("FATAL: don't know that kind of prim...($%x)\n",s);
				
				for (;;);
				break;

		}
		primitive += a;
		p--;
	}
}

#ifndef _WINDOWS




// CPW: #define DCACHE  0x1f800000
// CPW: #define DCACHETOP 0x1f800400 /*1k stack!*/



// CPW: #define DCACHE  0x1f800000
// CPW: #define DCACHETOP 0x1f800400

#ifndef _WINDOWS

#define GETX(n)( ((SHORTXY *)( (int)(tfv) +(n) ))->x )
#define GETY(n)( ((SHORTXY *)( (int)(tfv) +(n) ))->y )
#define GETV(n)(  *(u_long *)( (int)(tfv) +(n) ) )
#define GETD(n)(  *(u_long *)( (int)(tfd) +(n) ) )
#define GETN(n)( ((VERT *)( (int)(tfn) +(n<<1) )) )

#else

#define GETX(n)( ((SHORTXY *)( (int)(tfv) +(n<<2) ))->x )
#define GETY(n)( ((SHORTXY *)( (int)(tfv) +(n<<2) ))->y )
#define GETV(n)(  *(u_long *)( (int)(tfv) +(n<<2) ) )
#define GETD(n)(  *(u_long *)( (int)(tfd) +(n<<2) ) )
#define GETN(n)( ((VERT *)( (int)(tfn) +(n<<3) )) )

#endif




TextureType* PageTexture(USHORT ix)
{
	TextureType *sprt;

	if (!ix)
		return 0;

	ix--;

	sprt = textureFindCRCInAllBanks(utilStr2CRC((char*)&currentTextureList[ix]) );
	
	return sprt;

}





/**************************************************************************
	FUNCTION:	PSISortPrims
	PURPOSE:	create link list table for model's polys
	PARAMETERS:	
	RETURNS:	
**************************************************************************/

// If this rou's running out of registers, it may be worth
// allocating ourselves some scratchpad space
void customPsiSortPrimitives(long *tfv, long *tfd)
{
}



/**************************************************************************
	FUNCTION:	PSIDrawSegments
	PURPOSE:	draw all object segments of an actor
	PARAMETERS:	
	RETURNS:	
**************************************************************************/

// NB - This function uses the entire D-Cache for vertex transformation if the object fits...)
//void customPsiDrawSegments(PSIDATA *psiData)
void psiDrawSegments_NOT_THIS_ONE(PSIDATA *psiData)
{
	long		*tfvbase;
	long		*tfdbase;
	register long		*tfv;
	register long		*tfd;
	register PSIOBJECT	*world;
	PSIMODELCTRL		*modctrl = &PSImodelctrl;
	LONG				depth;
	LONG				s = modctrl->sorttable;
	int					loop, obs, i;
	VERT				*tfn;


	TIMER_START(TIMER_PSIREND);	// Our version of Timer can cope with restarting timers
	{
		PSIMODEL *model = (PSIMODEL *)psiData->modelName;
		if(*(unsigned int *)model == BFF_PSI1_ID)
		{
			direct2psiDrawSegments(psiData);
			TIMER_STOP(TIMER_PSIREND);

			return;
		}
	}

// Note - The Model Viewer still goes through here...
//	DB(" **** OLD PSI RENDERER ****\n");
//	ASSERT(0);

	world = psiData->object;
	obs = psiData->numObjects;

	// transform all the vertices (by heirarchy)
	// tfv == one long list of transformed vertices


	tfn = transformedNormals - 1;



	tfTotal = 0;
	for (loop = 0; loop < obs; loop++)
	{
		world = (PSIOBJECT*)psiData->objectTable[loop];
		tfTotal += world->meshdata->vern;
	}

	if(tfTotal <= 126)	// Not 128. TransformVerts rounds up to nearest 3, remember
	{
		tfvbase = (void *)DCACHE;
		tfdbase = (void *)(DCACHE + 512);
	}
	else if(tfTotal <= 255)	// Not 256. TransformVerts rounds up to nearest 3, remember
	{
		tfvbase = (void *)DCACHE;
		tfdbase = transformedDepths;
	}
	else
	{
		tfvbase = transformedVertices;
		tfdbase = transformedDepths;
	}


	tfv = tfvbase;
	tfd = tfdbase;

	tfTotal = 0;

	for (loop = 0; loop < obs; loop++)
	{
		world = (PSIOBJECT*)psiData->objectTable[loop];

	 	gte_SetRotMatrix(&world->matrixscale);		 
	   	gte_SetTransMatrix(&world->matrixscale);	

		gte_ldv0(&world->meshdata->center);

		gte_rtps();

		modctrl->NormTop = world->meshdata->nortop;
		

		gte_stszotz(&world->depth);

		transformVertexListA(world->meshdata->vertop, world->meshdata->vern, tfv, tfd );

		if(modctrl->lighting)
		{
			register SVECTOR	*np;
			gte_SetRotMatrix(&world->matrix);			 
			np = (SVECTOR*)world->meshdata->nortop;
	   		//gte_SetTransMatrix(&world->matrix);	

			for(i = world->meshdata->norn; i != 0; i--)
			{
				gte_ldv0(np);
				gte_rtv0();		// an 8 cycle job, with two nops preceding it
				np++;			// do stuff while the rt's going on
				tfn++;
//				gte_stsv(GETN(0));
			}
		}

		tfv += world->meshdata->vern;
		tfd += world->meshdata->vern;
		tfTotal += world->meshdata->vern;
	}

//	printf("tf = %d\n",tfTotal);


	modctrl->PrimTop = (ULONG*)psiData->primitiveList;

	/*
	j = modctrl->depthShift;

	if (j == 0)
	{
		j = DEFAULTDEPTHSHIFT;
	}
	*/

	if (psiData->flags & ACTOR_DYNAMICSORT)
	{
#ifndef _WINDOWS
	 	customPsiCalcMaxMin(psiData, tfdbase);
#else
		//PsiCalcMaxMin(psiData, tfdbase);
#endif


		world = (PSIOBJECT*)psiData->objectTable[0];

		if (modctrl->depthoverride)
		{
			depth = modctrl->depthoverride;
		}
		else
		{
			depth = world->depth;
		}
		
		modctrl->PrimLeft = psiData->noofPrims;
		modctrl->VertTop = world->meshdata->vertop;

//		if((depth >> modctrl->depthShift) < 0 || (depth >> modctrl->depthShift) > 1023)
//		{
//			DB("Depth Error %d!\n",depth);
//		}

		if((depth >> modctrl->depthShift) < 0)
			depth = 0;
			
		if((depth >> modctrl->depthShift) > 1023)
		{
			depth = 1023 << modctrl->depthShift;
		}



#ifndef _WINDOWS
		customPsiSortPrimitives(tfvbase,tfdbase);
#else
		//PsiSortPrimitives(tfvbase,tfdbase);
#endif

		modctrl->polysdrawn = sortCount;

		if(modctrl->lighting == DIRECTIONONLY)	// the mode we're using for all ingame models
		{
//	DB(" **** OLD DIRECTION-ONLY RENDERER ****\n");

#ifndef _WINDOWS
	  //		customPsiDrawSortedPrimitives(depth >> modctrl->depthShift, tfvbase);
#else
			//PsiDrawSortedPrims(depth >> modctrl->depthShift, tfvbase);
#endif
		}
		else
		{
//	DB(" **** OLD FULL-VERSION RENDERER (lighting = %d) ****\n",modctrl->lighting);
	   //		customPsiDrawSortedPrimitives_Full(depth >> modctrl->depthShift, tfvbase);
		}
	}
	else
	{
// speed optim version is not un-sorted-object compatable
		for (loop = 0; loop < obs; loop++)
		{
			world = (PSIOBJECT*)psiData->objectTable[loop];
	
			if (modctrl->depthoverride)
			{
				depth = modctrl->depthoverride;
			}
			else
			{
				depth = world->depth;
			}
	
			modctrl->VertTop = world->meshdata->vertop;
		 	modctrl->SortOffs = world->meshdata->sortlistptr[s];
			modctrl->PrimLeft = world->meshdata->sortlistsize[s];

//	DB(" **** OLD PER-MODEL-SORT RENDERER (which shouldn't work) ****\n",modctrl->lighting);

//			psiDrawPrimitives(depth >> modctrl->depthShift, tfvbase,tfdbase);
		}
	}
	TIMER_STOP(TIMER_PSIREND);
}



// =====================================================
// Direct copies from psi.c
// =====================================================

VECTOR *PSIrootScale = 0;
VECTOR *PSIactorScale = 0;
PSIMODELCTRL	PSImodelctrl;
int	biggestVertexModel=0;
int	biggestPrimModel=0;
long *transformedVertices = 0;
long *transformedDepths = 0;
VERT *transformedNormals = 0;
long maxDepth=0;
long minDepth=0;
int depthRange=0;
int maxDepthRange=0;
ULONG *sortedIndex=0;//[DEPTHINIT];
int sortCount=0;
int  tfTotal = 0;

int MAXMODELS;
int pilLibraryLen = 0;
long *pilLibraryList[8];
int	psiModelListLen = 0;
MATRIX		lightMat;
SVECTOR		lightRotVec;
GsF_LIGHT	flatLight[3];
long *psiModelListCRC;
PSIMODEL **psiModelList;
int TG4count=0;
int TG3count=0;
int TF4count=0;
int TF3count=0;
int F4count=0;
int F3count=0;
char *PSIname=0;
PSIMODEL *currentPSI;
PSITEXTURES	*currentTextureList;
void (*customDrawFunction)(int) = 0;
void (*customDrawFunction2)(int) = 0;



void psiInitSortList(int range)
{
	range = range * 2;
	if ( range<= maxDepthRange )
		return;

	printf("Initting range = %d\n",range);
	maxDepthRange = range;

	if(transformedVertices)
	{
		utilPrintf("Someone's trying to load a PSI after fixing psiAllocWorkspace\n");
//		CRASH;
		if (sortedIndex)
			FREE(sortedIndex);
		
		sortedIndex = (ULONG*)MALLOC( range*sizeof(ULONG));


	}

// Fred's moved this to "psiAllocWorkspace"
/*
	if (sortedIndex)
		FREE(sortedIndex);
	
	sortedIndex = (ULONG*)MALLOC( range*sizeof(ULONG));
*/

}

PSIOBJECT *psiObjectScan(PSIOBJECT *obj, char *name)
{
	PSIOBJECT *result;
	int crc;

	crc = utilStr2CRC(name);
	
	while (obj)
	{
//		utilUpperStr(obj->meshdata->name);

		if(MESH_NAMECRC(obj->meshdata) == crc)
		{
			return obj;
		}
//		if ( strcmp( obj->meshdata->name, name )==0 )
//			return obj;
		
		if ( obj->child )
		{
			 result = psiObjectScan(obj->child,name);
			 if (result)
				 return result;
		}

		obj = obj->next;

	}	

	return NULL;
}





void psiDestroy()
{

	FREE(transformedNormals);
	FREE(transformedDepths);
	FREE(transformedVertices);


	while (psiModelListLen)
	{
	 	psiModelListLen--;
	 	FREE(psiModelList[psiModelListLen]);
	}

	while (pilLibraryLen)
	{
		pilLibraryLen--;
	 	FREE(pilLibraryList[pilLibraryLen]);
	}

	transformedVertices = 0;
	transformedDepths = 0;
	transformedNormals = 0;
	biggestVertexModel = 0;
	biggestPrimModel = 0;
	
	if (sortedIndex)
		FREE(sortedIndex);

	sortedIndex = NULL;
	maxDepthRange = 0;

	FREE(psiModelList);
	FREE(psiModelListCRC);

	
}

void psiResetModelctrl()
{
	PSImodelctrl.depthoverride = 0;
	PSImodelctrl.specialmode = OFF;
	PSImodelctrl.onmap = 0;
	PSImodelctrl.col.r = 128;
	PSImodelctrl.col.g = 128;
	PSImodelctrl.col.b = 128;
	PSImodelctrl.sprites = YES;
	PSImodelctrl.nearclip = 100;
	PSImodelctrl.farclip = 16384;
	PSImodelctrl.inheritScale = 0;

}
void psiInitLights()
{

   	lightMat=GsIDMATRIX;
	lightRotVec.vx = 0;
	lightRotVec.vy = 0;
	lightRotVec.vz = 0;
	RotMatrixYXZ_gte(&lightRotVec,&lightMat);

	psiSetLight(0, 0,0,0, 0,0,0 );
	psiSetLight(1, 0,0,0, 0,0,0 );
	psiSetLight(2, 0,0,0, 0,0,0 );
	
 	GsSetAmbient(1024,1024,1024);
	GsSetLightMode(0);

}
void psiInitialise(int maxModels)
{

	psiResetModelctrl();

	psiInitSortList(256);

	psiInitLights();

	//actorList.numEntries = 0;
	//actorList.head.next = actorList.head.prev = &actorList.head;

	transformedVertices = 0;
	transformedDepths = 0;
	transformedNormals = 0;
	biggestVertexModel = 0;
	biggestPrimModel = 0;

	psiModelListLen = 0;
	pilLibraryLen = 0;

	customDrawFunction = 0;
	customDrawFunction2 = 0;

	psiModelList = MALLOC(sizeof(PSIMODEL *) * maxModels);
	psiModelListCRC =MALLOC(sizeof(long) * maxModels);
	MAXMODELS = maxModels;
}

void psiSetAmbient(int r, int g, int b)
{
	GsSetAmbient(r,g,b);
}
void psiSetLight(int lightNum, int r, int g, int b, int x, int y, int z)
{

	flatLight[lightNum].vx = x;
	flatLight[lightNum].vy = y;
	flatLight[lightNum].vz = z;
 	flatLight[lightNum].r  = r;
 	flatLight[lightNum].g  = g;
 	flatLight[lightNum].b  = b;
	GsSetFlatLight( lightNum, &flatLight[lightNum]);


   	lightMat=GsIDMATRIX;
	RotMatrixYXZ_gte(&lightRotVec,&lightMat);
	GsSetLightMatrix2(&lightMat);

}

void *psiRegisterDrawFunction(void (*drawHandler)(int))
{
	
	void *olddraw = (void *)customDrawFunction;

	customDrawFunction = drawHandler;

	return olddraw;
	
}
long psiCRCName(char *psiName)
{
	int i,j,slen;
	char str[64];

	utilUpperStr(psiName);
	
	for (i = 0; i < 63; i ++)
	{
		str[i] = psiName[i];
		if ( (psiName[i] == 0) || (psiName[i] == 32) || (psiName[i] == '.') )
			break;
	}
	str[i] = 0;
	slen = i - 1;

	for (i = slen; i >= 0; i --)
	{
		if ( ((str[i] < 'A') || (str[i] > 'Z')) &&
			 ((str[i] < '0') || (str[i] > '9')) )		 break;
	}

	if (i >= 0)
	{
		j = i + 1;
		for (i = 0; i < slen; i ++)
		{
		 str[i] = str[i + j];
		}
	}
	
	return utilStr2CRC(&str[0]);
}
PSIMODEL *psiCheck(char *psiName)
{
	int i,crc;

	crc = psiCRCName(psiName);

	for (i = 0; i < psiModelListLen; i ++)
	{
		if ( psiModelListCRC[i] == crc )
			return psiModelList[i];
	}

	return NULL;
}
PSIMODEL *psiLoad(char *psiName)
{
	char *addr;
	//PSIMESH *mesh;
	int lastfilelength;//,i;
	PSIMODEL *psiModel;


	if (sizeof(PSIMODEL) != 192)
		utilPrintf("\nWARNING: PSIMODEL structure length invalid (%d != 192)\n\n",sizeof(PSIMODEL));
	

	psiModel = psiCheck(psiName);		// already loaded ?
	if (psiModel!=NULL)
	{
		//utilPrintf("Already loaded file %s\n",psiName);
		//psiDisplay(psiModel);
		return psiModel;

	}

	PSIname = psiName;

	if (psiModelListLen>=MAXMODELS) 
	{
		utilPrintf("jees ! how many models do you expect me to load ?\n"); 
		return 0; 
	}


	//psiName = psiConstructName(psiName);
	addr = (void *)fileLoad(psiName, &lastfilelength);
	
	psiModel = psiFixup(addr);

	customPsiFixupPrims(psiModel);
	return psiModel;

}


void psiAllocWorkspace()
{
	transformedVertices = (long*)MALLOC( (biggestVertexModel + 2) * sizeof(long) );
	transformedDepths = (long*)MALLOC( (biggestVertexModel + 2) * sizeof(long) );
	transformedNormals = (VERT*)MALLOC( (biggestVertexModel + 2) * sizeof(VERT));

	if (sortedIndex)
		FREE(sortedIndex);
	sortedIndex = (ULONG*)MALLOC( maxDepthRange * sizeof(ULONG));

}


void psiFixupPrims_NOT_THIS_ONE(PSIMODEL *psiModel)
{
}


PSIMODEL *psiFixup(char *addr)
{
	PSIMESH *mesh;
	int i;
	PSIMODEL *psiModel;

	psiModel = (PSIMODEL*)addr;

	currentPSI = psiModel;

	// do check for "PSI",0
//	if(strcmp((char*)psiModel,"PSI")!=0){ utilPrintf("%s is not a valid PSI file.\n",addr); return 0; }

	// primitive offset pointer
	psiModel->primOffset += (int)addr;
	
	// list of texture names
	psiModel->textureOffset += (int)addr;
	
	// mesh offset
	psiModel->firstMesh += (int)addr;
	
	//	offset to anim frame list
	psiModel->animSegmentList += (int)addr;

	// malloc transformation vertex,normal and depth buffers to biggest
	// model vert count loaded so far
	i = psiModel->noofVerts;
	if ( i>biggestVertexModel )
	{
		biggestVertexModel = i;
	}

//	DisplayPSI(psiModel);

	// number of textures
	(char*)currentTextureList = (PSITEXTURES*)psiModel->textureOffset;

//	numoftextures = psiModel->noofTextures;
//	for (i=0; i<numoftextures; i++) utilPrintf("%d: %s\n",i,&textureList[i]);

	
	
	// PSI MESH LIST

	mesh = (PSIMESH*)psiModel->firstMesh;

	psiFixupMesh(mesh);
	psiFixupOneRoot(mesh);

	psiFixupPrims(psiModel);

//	utilPrintf("Load PSI done\n");

	// add to loaded model list (for checking re-loads)
	psiModelList[psiModelListLen] = psiModel;
//	strncpy( psiModelListNames[psiModelListLen], PSIname, 16);
	psiModelListCRC[psiModelListLen] = psiCRCName( PSIname );
	psiModelListLen++;


// A quick little fix so we have no differences in bff_load...
// Moved up a level
//	customPsiFixupPrims(psiModel);



	return psiModel;
}

#endif



// ===================================================================================
//                BFF PSI Stuff
// ===================================================================================
// (There's a couple of messy references to IslPsi internals here to get it to work quickly)

// the reason there's an extra "BFF_PsiStr"type is in case we ever need to split the bff header from the psi one
// (ie, if the psi library ever checks the model's version or flags words)

/*
extern int	psiModelListLen;	// A bit messy...
PSIMODEL *psiFixup(char *addr);
void BFF_Link_PSI(BFF_PsiStr *bffpsi)
{
	psiFixup((char *)bffpsi);
	customPsiFixupPrims((PSIMODEL *)bffpsi);

	// JS : Gahhh !! Freeeeed  !! How many bloody ways do we need to load models and levels !!
	// gahhhh !! I want to be lazy and fix it only once !! Gahhhhhh !!!
#ifdef _WINDOWS
	d2mnotReallyPCH3D_CreateList((PSIMODEL *)bffpsi);
#endif

 	psiModelListLen--;	// Stop the PSI library from trying to free BFF files. (Messy, but also removes the max-models limit from isl-psi)
}
*/


PSIMODEL * BFF_IsModelLoaded(char *modelname)
{
	BFF_PsiStr *bffpsi;
//	bffpsi = (void *)BFF_FindNamedObject(BFF_PSI_ID, modelname);
	bffpsi = (void *)BFF_FindNamedObject(BFF_PSI1_ID, modelname);
	if(!bffpsi)
		DB("Model not found\n");

	return(PSIMODEL *)bffpsi;

}
PSIMODEL * BFF_IsCRCModelLoaded(unsigned long crc)
{
	BFF_PsiStr *bffpsi;
//	bffpsi = (void *)BFF_FindObject(BFF_PSI_ID, crc);
	bffpsi = (void *)BFF_FindObject(BFF_PSI1_ID, crc);
	if(!bffpsi)
		DB("Model not found\n");
	return(PSIMODEL *)bffpsi;
}


