///////////////////////////////////////////////////////////////////////////////////////////
// curvegenerator.cpp BY:Donovan Walker
//
// This routine will generate a curved NxM rectangular 
// bezier mesh based on a 16 control point square matrix
//


#include "stdafx.h"
#include "Vector3D.h"
#include "Vector3DGroup.h"
#include "matrixmath.h"
#include "mesh.h"



void curveGenerator(/*out*/Mesh *pCurveMesh,/*in*/Mesh *pControlMesh,/*in*/float fNumXPoints,/*in*/float fNumZPoints) {
	
	MatrixMath matrix;

	//initialize variables
	Vector3DGroup *pControlVGroup;
	Vector3DGroup *pCurveVGroup;

	pControlVGroup = pControlMesh->getVector3DGroupPtr();
	pCurveVGroup = pCurveMesh->getVector3DGroupPtr();
	

	float *fControlGroupX = new float[pControlVGroup->getNumElements()];
	float *fControlGroupY = new float[pControlVGroup->getNumElements()];
	float *fControlGroupZ = new float[pControlVGroup->getNumElements()];
	float *fSMatrix = new float[4];
	float *fTMatrix = new float[4];
	float *fAnsMatrix = new float[4];
	float *fPointValueX  = new float;
	float *fPointValueY  = new float;
	float *fPointValueZ  = new float;
	float s = 0;
	float fOneMinusS = 0;
	float t = 0;
	float fOneMinusT = 0;
	int iControlPoints = 0;
	int iCurvePoints = 0;
	int i = 0;
	int j = 0;

	iControlPoints = pControlVGroup->getNumElements();
	iCurvePoints = pCurveVGroup->getNumElements();

	for(i = 0; i < 4; i++) {
		fSMatrix[i] = 0;
		fTMatrix[i] = 0;
	}

	//Copy the x,y,z coordinates into array matricies for bezier equation
	for(i = 0; i < iControlPoints ; i++) {
		fControlGroupX[i] = pControlVGroup->getElementAt(i).fX;
		fControlGroupY[i] = pControlVGroup->getElementAt(i).fY;
		fControlGroupZ[i] = pControlVGroup->getElementAt(i).fZ;
	}
	
	//Algorithmic implementation of bezier equation
	for(i = 0; i < fNumXPoints; i++) {
		fOneMinusS = 1 - s;
		fSMatrix[0] = fOneMinusS*fOneMinusS*fOneMinusS;
		fSMatrix[1] = 3*fOneMinusS*fOneMinusS*s;
		fSMatrix[2] = 3*fOneMinusS*s*s;
		fSMatrix[3] = s*s*s;

		t = 0; //move t back to the beginning for the next row
		for(j = 0; j < fNumZPoints; j++) {

			fOneMinusT = 1 - t;
			fTMatrix[0] = fOneMinusT*fOneMinusT*fOneMinusT;
			fTMatrix[1] = 3*fOneMinusT*fOneMinusT*t;
			fTMatrix[2] = 3*fOneMinusT*t*t;
			fTMatrix[3] = t*t*t;

			//X
			matrix.multiply(fSMatrix, 4, 1, fControlGroupX, 4, 4, fAnsMatrix);
			matrix.multiply(fAnsMatrix, 4, 1, fTMatrix, 1, 4, fPointValueX);
			//Y
			matrix.multiply(fSMatrix, 4, 1, fControlGroupY, 4, 4, fAnsMatrix);
			matrix.multiply(fAnsMatrix, 4, 1, fTMatrix, 1, 4, fPointValueY);
			//Z
			matrix.multiply(fSMatrix, 4, 1, fControlGroupZ, 4, 4, fAnsMatrix);
			matrix.multiply(fAnsMatrix, 4, 1, fTMatrix, 1, 4, fPointValueZ);
			pCurveVGroup->setElementAt(((i*fNumZPoints) + j), fPointValueX[0], fPointValueY[0], fPointValueZ[0]);
			
			t += 1/(fNumZPoints-1);
		}
		s += 1/(fNumXPoints-1);
	}	
}

