/****************************/
/*   	TEXTURE.C		    */
/* (c)2004 Pangea Software  */
/* By Brian Greenstone      */
/****************************/


/****************************/
/*    EXTERNALS             */
/****************************/


extern	EventRecord			gTheEvent;
extern	short				gHtab;
extern	FSSpec				gLast3DMF_FSSpec;
extern	Boolean				gFileContainsNonTriMesh;
extern	BG3DFileContainer		*gBG3DContainerList[];

/****************************/
/*    PROTOTYPES            */
/****************************/

static void RecursivelyParseObject(MetaObjectPtr obj);
static void RemoveDuplicateTexturesFromTriMesh(MOMeshObject *theTriMesh);
static MOMaterialObject *FindDuplicateMaterial(MOMaterialObject *inMat);
static Boolean CompareTexturePixels(MOMaterialData *t1, MOMaterialData *t2);


/****************************/
/*    CONSTANTS             */
/****************************/




/*********************/
/*    VARIABLES      */
/*********************/

long					gNumMaterials = 0;
MaterialType			gMaterialsList[MAX_MATERIALS];
long					gNumDupeMaterials;


/********************* INIT MATERIALS LIST *************************/

void InitMaterialsList(void)
{
long	i;

				/* INIT TEXTURE LIST */
				
	for (i=0; i < gNumMaterials; i++)
	{
		DisposeGWorld(gMaterialsList[i].gworld);
		DisposeWindow(gMaterialsList[i].window);
		
	}
	gNumMaterials = 0;
	
	gNumDupeMaterials = 0;
}


/**************************** REMOVE DUPLICATE MATERIALS *********************************/

void RemoveDuplicateMaterials(void)
{
			/* RECURSIVELY PARSE THRU OBJECT */
			
	RecursivelyParseObject(gBG3DContainerList[0]->root);
	
}


/****************** RECURSIVELY PARSE OBJECT ***********************/

static void RecursivelyParseObject(MetaObjectPtr obj)
{
MetaObjectPtr  		subObj;
MetaObjectHeader	*header;

				/* SEE IF FOUND GEOMETRY */

	header = (MetaObjectHeader *)obj;

	if (header->type == MO_TYPE_MESH)
	{
		RemoveDuplicateTexturesFromTriMesh(obj);
	}

			/* SEE IF RECURSE SUB-GROUP */

	else
	if (header->type == MO_TYPE_GROUP)
 	{
 		MOGroupObject	*groupObj = (MOGroupObject *)obj;
 		int				i;
 		
  		for (i = 0; i < groupObj->objectData.numObjectsInGroup; i++)	// scan all objects in group
 		{
 			subObj = groupObj->objectData.groupContents[i];
   			RecursivelyParseObject(subObj);								// sub-recurse this object
  		}
	}
}



/****************** REMOVE DUPLICATE TEXTURES FROM TRIMESH *********************/

static void RemoveDuplicateTexturesFromTriMesh(MOMeshObject *theTriMesh)
{
MOMeshData	*meshData = &theTriMesh->objectData;
MOMaterialObject	*dupMat;

	if (meshData->material == nil)									// does this mesh have a material?
		return;


		/* SEE IF THIS MATERIAL IS THE DUPLICATE OF ONE WE ALREADY HAVE */
		
	dupMat = FindDuplicateMaterial(meshData->material);				// look for a dupe
	if (dupMat)														// if found it, then replace this with it
	{
		MO_DisposeObjectReference(meshData->material);				// dispose of the old material object
	
		meshData->material = MO_GetNewReference(dupMat);			// reassign to existing material while incrementing ref count
	}
}


/********************* FIND DUPLICATE MATERIAL *************************/

static MOMaterialObject *FindDuplicateMaterial(MOMaterialObject *inMat)
{
int				i;
u_long			flags;
OGLColorRGBA	diffuseColor;			
u_long			width,height;
Boolean			hasTexture;		
MOMaterialData	*inData = &inMat->objectData;

				/* GET INFO ON INPUT TEXTURE */
				
	flags 			= inData->flags;
	diffuseColor 	= inData->diffuseColor;
	width 			= inData->width;
	height			= inData->height;
	hasTexture		= inData->hasTexture;
				

			/************************/
			/* LOOK FOR A DUPLICATE */
			/************************/			
			
	for (i = 0; i < gNumMaterials; i++)
	{
		MOMaterialData	*mat = &gMaterialsList[i].materialObj->objectData;	// get ptr to this material object's data in list
		
	
				/* DO SIMPLE ELIMINATION CHECKS */

		if (gMaterialsList[i].materialObj == inMat)							// if this is pointing directly to an existing material then just bail
			return(nil);

		if (mat->flags != flags)											// see if different flags
			continue;
			
		if ((mat->diffuseColor.r != inData->diffuseColor.r) ||				// see if different RGBA color
			(mat->diffuseColor.g != inData->diffuseColor.g) ||
			(mat->diffuseColor.b != inData->diffuseColor.b) ||
			(mat->diffuseColor.a != inData->diffuseColor.a))
			continue;

				/* DO TEXTURE COMPARISONS */

		if (mat->hasTexture != hasTexture)									// see if texture flag same
			continue;
							
		if (hasTexture)
		{
			if (mat->width != width)										// textures must be same size
				continue;
			if (mat->height != height)
				continue;
								
			if (!CompareTexturePixels(inData, mat))							// now compare the pixel buffers themselves
				continue;	
		
		}

			/*********************************/
			/* THESE MATERIALS ARE IDENTICAL */
			/*********************************/

		return(gMaterialsList[i].materialObj);								// return the material obj that was already in the list	
	}


			/****************************************************/
			/* NO MATCH FOUND, SO ADD THIS MATERIAL TO THE LIST */
			/****************************************************/

	if (gNumMaterials >= MAX_MATERIALS)										// check for overflow
		DoFatalAlert("\p# of materials exceeds MAX_MATERIALS!");

	gMaterialsList[gNumMaterials].materialObj = inMat;						// set ILLEGAL reference to the material

	gMaterialsList[gNumMaterials].window = nil;
	gMaterialsList[gNumMaterials].gworld = nil;
	
	gNumMaterials++;
	
	return(nil);
}


/*************************** COMPARE TEXTURE PIXELS *********************************/
//
// returns true if identical
//

static Boolean CompareTexturePixels(MOMaterialData *t1, MOMaterialData *t2)
{
int		w,h;
int		size,i;
Ptr		p1,p2;

			/* DETERMINE SIZE OF BUFFERS TO COMPARE */
			
	w = t1->width;
	h = t1->height;

	size = w * h * 4;
			

			/* COMPARE PIXELS */
			
	p1 = t1->texturePixels;
	p2 = t2->texturePixels;
			
	for (i = 0; i < size; i++)
	{
		if (p1[i] != p2[i])
			return(false);
	}

	return(true);
}


