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


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


extern	int				gNumMaterials;
extern	MOMaterialObject	*gMaterials[];
extern	FSSpec			gExportSpec;
extern	MOMeshObject			*gVertexArrayObjects[];
extern	Boolean			gExportLayersSeparate;

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

static void WriteBG3DHeader(short refNum);
static void WriteBG3DMaterials(short refNum);
static void WriteBG3DGeometry(short refNum);
static void WriteNormalArray(short refNum, OGLVector3D *vectors, int numPoints);
static void WriteColorArray(short refNum, OGLColorRGBA_Byte *colors, int numPoints);
static void WriteBG3DEndTag(short refNum);
static void WriteTexture(short refNum, MOMaterialData *data);

static void WriteAVertexArray(int materialNum, short refNum, MOMeshObject *obj);
static void WriteUVArray(short refNum, OGLTextureCoord *uvs, int numPoints);

static void WriteBG3DMaterials(short refNum);


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

#define	MAX_GEOMETRIES	1000


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


static	int		gSurfaceToExportedMaterialTable[MAX_SURFACES];

ImageDescriptionHandle	gQTImageDescHandle = nil; 
Ptr						gQTCompressedImageData = nil;


/********************** SAVE BG3D MODEL **************************/

void SaveBG3DModel(void)
{
OSErr	iErr;
short	refNum;

			/* OPEN FILE */
		
	FSpDelete(&gExportSpec);									// delete any old one
	FSpCreate(&gExportSpec, 'BGLk', 'BG3D', smSystemScript);	// create new file
	iErr = FSpOpenDF(&gExportSpec, fsWrPerm, &refNum);		// open file
	if (iErr)
		return;
				
	
			/* WRITE ALL THE COMPONENTS */
			
	WriteBG3DHeader(refNum);
	WriteBG3DMaterials(refNum);
	WriteBG3DGeometry(refNum);

	
			/* CLOSE FILE */
			
	WriteBG3DEndTag(refNum);
	FSClose(refNum);
}


#pragma mark -

/********************** WRITE BG3D HEADER **************************/

static void WriteBG3DHeader(short refNum)
{
BG3DHeaderType	headerData;
char			s[16] = "BG3D 1.0        ";
long			count;


			/* SET HEADER FIELDS */
			
	BlockMove(&s[0], &headerData.headerString[0], 16);		// set header string
	
	headerData.version.majorRev 		= 0x01;
	headerData.version.minorAndBugRev 	= 0x00;
	headerData.version.stage 			= 0x00;
	headerData.version.nonRelRev	 	= 0x00;


			/* WRITE HEADER TO FILE */
	
	count = sizeof(BG3DHeaderType);			
	if (FSWrite(refNum, &count, &headerData) != noErr)
	{
//		DoFatalAlert("\pWriteBG3DHeader: FSWrite failed!");
	}
}


/********************** WRITE BG3D END TAG **************************/

static void WriteBG3DEndTag(short refNum)
{
u_long			tag;
long			count;

	tag = BG3D_TAGTYPE_ENDFILE;
	count = sizeof(tag);
	FSWrite(refNum, &count, &tag);							// write tag
}
	
/********************** WRITE BG3D MATERIALS **************************/

static void WriteBG3DMaterials(short refNum)
{
long			i;
long			count;
u_long			tag;
int				numExportedMaterials;
	
	numExportedMaterials = 0;									// assume no materials going out
	
	for (i = 0; i < gNumMaterials; i++)
	{
		MOMaterialObject	*obj = gMaterials[i];
		MOMaterialData		*data = &obj->objectData;
		Boolean				hasAlpha;
			
		if (!gVertexArrayObjects[i])							// dont write this surface/material if not being used
		{
			gSurfaceToExportedMaterialTable[i] = -1;
			continue;
		}

			/*************************/
			/* WRITE MATERIALS FLAGS */
			/*************************/
		

		/* DETERMINE IF NEED TO SET THE BLEND FLAG FOR TEXTURES W/ ALPHA */
				
		hasAlpha = false;
		if (data->flags & BG3D_MATERIALFLAG_TEXTURED)
		{	
			hasAlpha = TextureARGBContainsAlpha(data->width, data->height, data->texturePixels);	// if texture has an active alpha channel then also set the blend flag
			if (hasAlpha)
				data->flags |= BG3D_MATERIALFLAG_ALWAYSBLEND;
		}		
		
			/* WRITE TAG & FLAGS TO FILE */
		
		tag 	= BG3D_TAGTYPE_MATERIALFLAGS;
		count 	= sizeof(tag);
		FSWrite(refNum, &count, &tag);							// write tag
		count 	= sizeof(u_long);
		FSWrite(refNum, &count, &data->flags);					// write flags


			/****************************/
			/* WRITE DIFFUSE COLOR INFO */
			/****************************/
						
		tag 	= BG3D_TAGTYPE_MATERIALDIFFUSECOLOR;
		count 	= sizeof(tag);
		FSWrite(refNum, &count, &tag);							// write tag
		count 	= sizeof(float) * 4;
		FSWrite(refNum, &count, &data->diffuseColor);			// write diffuse color
			
			
			/**********************/
			/* WRITE TEXTURE INFO */
			/**********************/
			
		if (data->flags & BG3D_MATERIALFLAG_TEXTURED)
		{		
			WriteTexture(refNum, data);
		}			
		
				/* MAKE XLATE TABLE FOR LATER */
				
		gSurfaceToExportedMaterialTable[i] = numExportedMaterials;
		numExportedMaterials++;
		
		
	}
}



/************************ WRITE TEXTURE **********************/

static void WriteTexture(short refNum, MOMaterialData *data)
{
long		size;
int			w,h;
long		count;
u_long		tag;
BG3DTextureHeader	textureHeader;

	w = data->width;
	h = data->height;

	size = w * h * 4;


		/*******************************/
		/* COPY PIXEL DATA INTO BUFFER */
		/*******************************/



		/* SETUP TEXTURE HEADER */

	textureHeader.width 			= w;
	textureHeader.height 			= h;
	textureHeader.bufferSize 		= size;


	/* WRITE TAG, HEADER, AND TEXTURE TO FILE */
	
	tag 	= BG3D_TAGTYPE_TEXTUREMAP;
	count 	= sizeof(tag);
	FSWrite(refNum, &count, &tag);						// write tag
	
	count 	= sizeof(BG3DTextureHeader);
	FSWrite(refNum, &count, &textureHeader);			// write header

	FSWrite(refNum, &size, data->texturePixels);		// write texture
}




/******************** WRITE BG3D GEOMETRY ***********************/

static void WriteBG3DGeometry(short refNum)
{
int	i;
Boolean	grouping = false;
long			count;
u_long			tag;

	if ((gNumMaterials > 1) && (!gExportLayersSeparate))			// if we have multiple geometry, then be sure to group them
		grouping = true;


			/* WRITE GROUP START TAG */
			
	if (grouping)
	{
		tag 	= BG3D_TAGTYPE_GROUPSTART;
		count 	= sizeof(tag);
		FSWrite(refNum, &count, &tag);
	}


			/* WRITE THE GEOMETRY */
			
	for (i = 0; i < gNumMaterials; i++)								// there's one mesh per each material
	{
		if (!gVertexArrayObjects[i])								// skip any blanks
			continue;

		WriteAVertexArray(i, refNum,gVertexArrayObjects[i]);		// write this vertex array
	}
	
			/* WRITE GROUP END TAG */
			
	if (grouping)
	{
		tag 	= BG3D_TAGTYPE_GROUPEND;
		count 	= sizeof(tag);
		FSWrite(refNum, &count, &tag);
	}
}



/********************** WRITE A VERTEX ARRAY **************************/

static void WriteAVertexArray(int surfaceNum, short refNum, MOMeshObject *obj)
{
MOMeshData	*data = &obj->objectData;
long				count;
u_long				tag;
BG3DMeshHeader		header;

		/*************************/
		/* WRITE NEW MESH HEADER */
		/*************************/

	tag 	= BG3D_TAGTYPE_MESH;
	count 	= sizeof(tag);
	FSWrite(refNum, &count, &tag);

	header.materialNum			= gSurfaceToExportedMaterialTable[surfaceNum];
	header.flags 				= 0;
	header.numPoints 			= data->numPoints;
	header.numTriangles 		= data->numTriangles;

	count = sizeof(BG3DMeshHeader);
	FSWrite(refNum, &count, &header);


		/**********************/
		/* WRITE VERTEX ARRAY */
		/**********************/
			
			/* WRITE TAG */
			
	tag 	= BG3D_TAGTYPE_VERTEXARRAY;
	count 	= sizeof(tag);
	FSWrite(refNum, &count, &tag);
	

		/* WRITE VERTEX DATA */
		
	count = sizeof(OGLPoint3D) * header.numPoints;
	FSWrite(refNum, &count, data->points);


		/*************************/
		/* WRITE OPTIONAL ARRAYS */
		/*************************/

			/* VERTEX NORMALS */
			
	if (data->normals)
		WriteNormalArray(refNum, data->normals, header.numPoints);

			/* UVS */
			
	if (data->uvs)
		WriteUVArray(refNum, data->uvs, header.numPoints);


			/* VERTEX COLORS */
			
	if (data->colorsByte)
		WriteColorArray(refNum, data->colorsByte, header.numPoints);

	

		/******************************/
		/* WRITE TRIANGLE INDEX ARRAY */
		/******************************/

			/* WRITE TAG */
			
	tag 	= BG3D_TAGTYPE_TRIANGLEARRAY;
	count 	= sizeof(tag);
	FSWrite(refNum, &count, &tag);


		/* WRITE INDEX DATA */
		
	count = sizeof(MOTriangleIndecies) * header.numTriangles;
	FSWrite(refNum, &count, data->triangles);


}


/******************* WRITE NORMAL ARRAY **********************/

static void WriteNormalArray(short refNum, OGLVector3D *vectors, int numPoints)
{
long			count;
u_long			tag;

			/* WRITE TAG */
			
	tag = BG3D_TAGTYPE_NORMALARRAY;
	count = sizeof(tag);
	FSWrite(refNum, &count, &tag);
	

		/* WRITE VERTEX DATA */

	count = sizeof(OGLVector3D) * numPoints;
	FSWrite(refNum, &count, vectors);
}


/******************* WRITE UV ARRAY **********************/

static void WriteUVArray(short refNum, OGLTextureCoord *uvs, int numPoints)
{
long			count;
u_long			tag;

			/* WRITE TAG */
			
	tag = BG3D_TAGTYPE_UVARRAY;
	count = sizeof(tag);
	FSWrite(refNum, &count, &tag);
	

		/* WRITE VERTEX DATA */

	count = sizeof(OGLTextureCoord) * numPoints;
	FSWrite(refNum, &count, uvs);
}


/******************* WRITE COLOR ARRAY **********************/

static void WriteColorArray(short refNum, OGLColorRGBA_Byte *colors, int numPoints)
{
long			count;
u_long			tag;
	

			/* WRITE TAG */
			
	tag = BG3D_TAGTYPE_COLORARRAY;
	count = sizeof(tag);
	FSWrite(refNum, &count, &tag);
	

		/* WRITE COLOR DATA */

	count = sizeof(OGLColorRGBA_Byte) * numPoints;
	FSWrite(refNum, &count, colors);

}


#pragma mark -




/***************** TEXTURE CONTAINS ALPHA *********************/
//
// Returns TRUE if the input 32-bit ARGB texture buffer has any non-0xff alphas
//

Boolean TextureARGBContainsAlpha(short width, short height, u_long *data)
{
long	size, i;
u_long	pixel, alpha;

	size = width * height;

	for (i = 0; i < size; i++)
	{
		pixel = data[i];								// get ARGB pixel
		alpha = (pixel >> 24) & 0xff;					// extract alpha
		if (alpha != 0xff)								// is alpha not 100% opaque?
			return(true);
	}
	return(false);
}




















