/****************************************************************************************

		Star.cpp

		Copyright (c)1990 - 1999 MetaCreations. All rights reserved.

		Definitions shared by the C++ files and the resource definition files (.r)


		Author:	Jerome Bignon

		Date:	04/30/99

		Revision History

		when		who			what & why
		==========	==========	======================================================
		08/20/99	cph			Put in Extension3DInit() and Extension3DCleanup() methods
		07/13/99	Jeome		Solved the problem of invalide normal + all facet appear
								in the interactive renderer
		05/08/99	Jerome		Solved problems with the getUVSpace methods
		04/30/99	Jerome		Creation

*****************************************************************************************/

#include "math.h"
#include "Star.h"
#include "PublicUtilities.h"


const MCGUID CLSID_Star(R_CLSID_Star);

// Function that allow us to fill the FacetMeshAccumulator

FacetMeshAccumulator MakeStarFacet( FacetMeshAccumulator MeshAcc, TFacet3D Facet, 
				int16 FirstVertice, int16 SecondVertice, int16 NbBranches )
{
	short i, j;
	TVector3 normal;
	real angle,anglestep,radius1,radius2,radiusswap,sinus,cosinus;
	real k360=3.1415926535897932384626233f * 2.0f;
    
	angle=0.0f;
	anglestep=k360/((real)NbBranches) * 0.5f;
	radius1=10.0f;
	radius2=4.0f;

	for (i = 0; i < NbBranches*2; i++)
	{ 
		
		// Variable information of the common vertex                     
		Facet.fUVSpace=0;
		Facet.fVertices[0].fUV[1]=(((real)i)+0.5f)/((real)NbBranches*2);
		
		// Second Vertex information
		sinus=sin(angle);
		cosinus=cos(angle); //QuickSinCos(angle,sinus,cosinus);
		Facet.fVertices[FirstVertice].fVertex[0]=cosinus*radius1;
		Facet.fVertices[FirstVertice].fVertex[1]=sinus*radius1;
		Facet.fVertices[FirstVertice].fVertex[2]=0.0;
		Facet.fVertices[FirstVertice].fUV[0]=0.5;
		Facet.fVertices[FirstVertice].fUV[1]=((real)i)/((real)NbBranches*2); //angle/k360;
		
		// Last Vertex information
		angle += anglestep;
		sinus=sin(angle);
		cosinus=cos(angle); //QuickSinCos(angle,sinus,cosinus);
		Facet.fVertices[SecondVertice].fVertex[0]=cosinus*radius2;
		Facet.fVertices[SecondVertice].fVertex[1]=sinus*radius2;
		Facet.fVertices[SecondVertice].fVertex[2]=0.0;
		Facet.fVertices[SecondVertice].fUV[0]=0.5;
		Facet.fVertices[SecondVertice].fUV[1]=angle/k360;
		
		// Swap the radius to "alternate" the point
		radiusswap=radius1;radius1=radius2;radius2=radiusswap;
		
		// Normal vector calculation
		normal = (Facet.fVertices[1].fVertex - Facet.fVertices[0].fVertex) ^ 
						(Facet.fVertices[2].fVertex - Facet.fVertices[0].fVertex);

		real norm=sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
		normal[0] /= norm;
		normal[1] /= norm;
		normal[2] /= norm; // Normalization

		for (j=0; j<3; j++)
		{
			Facet.fVertices[j].fNormal=normal; // the 3 points have the same normal vector
		}
		
		// callback is used to give a facet to the shell
		Facet.fVertices[0].fUV[0]=1.0;

		MeshAcc.AccumulateFacet(&Facet);
	}
	return MeshAcc;
}


//----------------------------------------------------------------------------------------------------------------------
// Method of the Facet primitive

void Extension3DInit(IMCUnknown* utilities)
{
	// Perform your dll initialization here
}

void Extension3DCleanup()
{
	// Perform any nec clean-up here
}

TBasicUnknown* MakeCOMObject(const MCCLSID& classId)	// This method instanciate
{														// the object Star
	TBasicUnknown* res = NULL;

	if (classId == CLSID_Star) res = new Star;

	return res;
}


// Constructor of the C++ Object :

Star::Star()
{
	fData.fNbBranches=5;
	fData.fScalingFactor=1;
}
  
// IExDataExchanger methods :
  
void* Star::GetExtensionDataBuffer()
{
	return &fData;
}
    
// I3DExGeometricPrimitive methods
// -- Geometry calls


MCCOMErr Star::GetNbrLOD(int16 &nbrLod)
{
	nbrLod = 1;
	return MC_S_OK;
}
 
 
MCCOMErr Star::GetFacetMesh (uint32 lodIndex, FacetMesh** outMesh)
{
	TFacet3D starFacet;
	TVector3 normal;
	FacetMeshAccumulator starMeshAcc;

	real angle,anglestep,radius1,radius2;//,radiusswap,sinus,cosinus;
	real k360=3.1415926535897932384626233f * 2.0f;
    
	angle=0.0f;
	anglestep=k360/((real)fData.fNbBranches) * 0.5f;
	radius1=10.0f;
	radius2=4.0f;

	// Inferior Facets
	// -- Common Vertex of each inferior facets
	starFacet.fVertices[0].fVertex[0]=0.0f;
	starFacet.fVertices[0].fVertex[1]=0.0f;
	starFacet.fVertices[0].fVertex[2]=-4.0f;

	starMeshAcc = MakeStarFacet( starMeshAcc, starFacet, 2, 1, fData.fNbBranches );

	// Superior Facets
	// -- We change the z value for the common Vertice of superiors Facets
	starFacet.fVertices[0].fVertex[2]=4.0;

	starMeshAcc = MakeStarFacet( starMeshAcc, starFacet, 1, 2, fData.fNbBranches );

	starMeshAcc.MakeFacetMesh(outMesh);

	return MC_S_OK;
}
// Give the boundary Box
void Star::GetBoundingBox(TBBox3D& bbox)
{
	bbox.fMin[0]=-10.0;
	bbox.fMax[0]=10.0;
	bbox.fMin[1]=-10.0;
	bbox.fMax[1]=10.0;
	bbox.fMin[2]=-4.0;
	bbox.fMax[2]=4.0;
}
  
// -- Shading calls
uint32 Star::GetUVSpaceCount() 
{
	return 1; // the star is describe with only 1 UV-Space
}

MCCOMErr Star::GetUVSpaceRDS5(uint32 uvSpaceID, UVSpaceInfoRDS5* uvSpaceInfo) 
{
	if (uvSpaceID == 0)
	{ 
		uvSpaceInfo->fMin[0] = 0.0;				// u coordinate goes from 0 to 1
		uvSpaceInfo->fMax[0] = 1.0;
		uvSpaceInfo->fMin[1] = 0.0;				// v coordinate goes from 0 to 1
		uvSpaceInfo->fMax[1] = 1.0;
		uvSpaceInfo->fWraparound[0] = false;	// No Wrap around
		uvSpaceInfo->fWraparound[1] = false;
  }
  return MC_S_OK;
}

MCCOMErr Star::GetUVSpace(uint32 uvSpaceID, UVSpaceInfo* uvSpaceInfo) 
{
	if (uvSpaceID == 0)
	{ 
		uvSpaceInfo->fWraparound[0] = false;	// No Wrap around
		uvSpaceInfo->fWraparound[1] = false;
  }
  return MC_S_OK;
}
