/**
 * Render a debug circle on the screen (Y axis is normal to the circle)
 *
 * @param inLocation		World space location of the circle
 * @param inRotation		Rotation of the circle (Y axis is normal to the circle)
 * @param inRadius			The radius of the circle
 * @param withColor			The color of the circle
 * @param inSegments		Number of segments to divide the circle into
 * @param bShaded			Whether to shade the inside of the circle
 */
void RenderManager::DrawDebugCircle(const Vec4f& inLocation, const Quaternion& inRotation, const float inRadius, const ColorVector& withColor, const int inSegments, const bool bShaded) 
{
	const Matrix4x4 rotMatrix = inRotation.GetRotationMatrix();
	const Vec4f xAxis = rotMatrix.GetXAxis();
	const Vec4f zAxis = rotMatrix.GetZAxis();
	const float theta = 2*PI/inSegments;

	// Generate the circle vertices
	Vec4f* circleVerts = new Vec4f[inSegments];

	float currTheta = 0.f;
	for(int i=0; i<inSegments; i++, currTheta+=theta)
	{
		circleVerts[i] = inLocation + inRadius*cos(currTheta)*xAxis + inRadius*sin(currTheta)*zAxis;
	}

	for(int i=0; i<inSegments; i++)
	{
		DrawDebugLine(circleVerts[i], circleVerts[(i+1)%inSegments], withColor);
	}

	if(bShaded)
	{
		for(int i=0; i<inSegments; i++)
		{
			DrawDebugLine(inLocation, circleVerts[i], ColorVector::Black);
		}
	}

	delete[] circleVerts;
}
/**
 * Render a debug cube on the screen
 *
 * @param inLocation		World space location of the cube
 * @param inRotation		Rotation of the cube
 * @param inSize			The length, width and height of the cube
 * @param withColor			The color of the cube
 */
void RenderManager::DrawDebugCube(const Vec4f& inLocation, const Quaternion& inRotation, const Vec3f& inSize, const ColorVector& withColor)
{
	const Matrix4x4 rotMatrix = inRotation.GetRotationMatrix();
	const Vec4f xAxis = rotMatrix.GetXAxis();
	const Vec4f yAxis = rotMatrix.GetYAxis();
	const Vec4f zAxis = rotMatrix.GetZAxis();
	const Vec3f halfSize = inSize/2.f;

	// Generate the cube vertices
	Vec4f cubeVerts[8];
	cubeVerts[0] = inLocation - halfSize.x*xAxis - halfSize.y*yAxis - halfSize.z*zAxis;
	cubeVerts[1] = inLocation - halfSize.x*xAxis - halfSize.y*yAxis + halfSize.z*zAxis;
	cubeVerts[2] = inLocation + halfSize.x*xAxis - halfSize.y*yAxis + halfSize.z*zAxis;
	cubeVerts[3] = inLocation + halfSize.x*xAxis - halfSize.y*yAxis - halfSize.z*zAxis;
	cubeVerts[4] = inLocation - halfSize.x*xAxis + halfSize.y*yAxis - halfSize.z*zAxis;
	cubeVerts[5] = inLocation - halfSize.x*xAxis + halfSize.y*yAxis + halfSize.z*zAxis;
	cubeVerts[6] = inLocation + halfSize.x*xAxis + halfSize.y*yAxis + halfSize.z*zAxis;
	cubeVerts[7] = inLocation + halfSize.x*xAxis + halfSize.y*yAxis - halfSize.z*zAxis;

	// Render the cube edges
	DrawDebugLine(cubeVerts[0], cubeVerts[1], withColor); 
	DrawDebugLine(cubeVerts[1], cubeVerts[2], withColor);
	DrawDebugLine(cubeVerts[2], cubeVerts[3], withColor);
	DrawDebugLine(cubeVerts[3], cubeVerts[0], withColor);
	DrawDebugLine(cubeVerts[4], cubeVerts[5], withColor);
	DrawDebugLine(cubeVerts[5], cubeVerts[6], withColor);
	DrawDebugLine(cubeVerts[6], cubeVerts[7], withColor);
	DrawDebugLine(cubeVerts[7], cubeVerts[4], withColor);
	DrawDebugLine(cubeVerts[0], cubeVerts[4], withColor);
	DrawDebugLine(cubeVerts[1], cubeVerts[5], withColor);
	DrawDebugLine(cubeVerts[2], cubeVerts[6], withColor);
	DrawDebugLine(cubeVerts[3], cubeVerts[7], withColor);
}
/**
 * Render debug coordinated axes on the screen (Color code: x - red, y - green, z - blue)
 *
 * @param inLocation		World space location of the axes
 * @param inRotation		Rotation of the axes
 * @param inSize			The length, width and height of the axes
 */
void RenderManager::DrawDebugAxes(const Vec4f& inLocation, const Quaternion& inRotation, const Vec3f& inSize) 
{
	const Matrix4x4 rotMatrix = inRotation.GetRotationMatrix();
	const Vec4f xAxis = rotMatrix.GetXAxis();
	const Vec4f yAxis = rotMatrix.GetYAxis();
	const Vec4f zAxis = rotMatrix.GetZAxis();

	// Render the axes
	DrawDebugLine(inLocation, inLocation + inSize.x*xAxis, ColorVector::Red); 
	DrawDebugLine(inLocation, inLocation + inSize.y*yAxis, ColorVector::Green); 
	DrawDebugLine(inLocation, inLocation + inSize.z*zAxis, ColorVector::Blue); 
}
/**
 * Render a debug plane on the screen (Y axis is normal to the plane)
 *
 * @param inLocation		World space location of the plane
 * @param inRotation		Rotation of the plane (Y axis is normal to the plane)
 * @param inSize			The size of the plane
 * @param withColor			The color of the cube
 * @param bShaded			Shade the inside of the plane
 * @param inGridDivs		Number of grid lines to render inside the plane
 * @param bShaded			Whether to shade the inside of the plane
 * @param inGridDivs		Granularity of the shading
 */
void RenderManager::DrawDebugPlane(const Vec4f& inLocation, const Quaternion& inRotation, const float inSize, const ColorVector& withColor, const bool bShaded, const int inGridDivs) 
{
	const Matrix4x4 rotMatrix = inRotation.GetRotationMatrix();
	const Vec4f xAxis = rotMatrix.GetXAxis();
	const Vec4f zAxis = rotMatrix.GetZAxis();
	const float halfSize = inSize/2.f;
	
	// Generate the plane vertices
	Vec4f planeVerts[4];
	planeVerts[0] = inLocation - halfSize*xAxis - halfSize*zAxis;  
	planeVerts[1] = inLocation - halfSize*xAxis + halfSize*zAxis;
	planeVerts[2] = inLocation + halfSize*xAxis + halfSize*zAxis;
	planeVerts[3] = inLocation + halfSize*xAxis - halfSize*zAxis;

	// Render the plane edges
	DrawDebugLine(planeVerts[0], planeVerts[1], withColor); 
	DrawDebugLine(planeVerts[1], planeVerts[2], withColor); 
	DrawDebugLine(planeVerts[2], planeVerts[3], withColor); 
	DrawDebugLine(planeVerts[3], planeVerts[0], withColor); 

	if(bShaded)
	{
		const float gridSize = inSize/(float)inGridDivs;

		// Generate the subdivided vertices
		Vec4f* gridDivs = new Vec4f[4*(inGridDivs-1)];
		for(int i=0; i<4; i++)
		{
			const Vec4f& start = planeVerts[i];
			const Vec4f& end = planeVerts[(i+1)%4];
			for(int j=0; j<inGridDivs-1; j++)
			{
				gridDivs[i*(inGridDivs-1) +j] = start + (j+1)*gridSize*((end-start).Normalize());		
			}
		}

		// Render the grid
		DrawDebugLine(planeVerts[0], planeVerts[2], ColorVector::Black); 
		for(int edgeIndex=0; edgeIndex<4; edgeIndex+=2)
		{
			int nextEdgeIndex = (edgeIndex+1)%4;

			for(int divIndex=0; divIndex<inGridDivs-1; divIndex++)
			{
				DrawDebugLine(gridDivs[edgeIndex*(inGridDivs-1) + divIndex], gridDivs[nextEdgeIndex*(inGridDivs-1) + (inGridDivs-2-divIndex)], ColorVector::Black); 
			}
		}

		delete[] gridDivs;
	}
}
/**
 * Render a debug cylinder on the screen (The axis of the cylinder is along the Y axis)
 *
 * @param inLocation		World space location of the cylinder
 * @param inRotation		Rotation of the cylinder (The axis of the cylinder is along the Y axis)
 * @param inRadius			The radius of the cylinder
 * @param inHeight			The height of the cylinder
 * @param withColor			The color of the cylinder
 * @param inSegments		Number of segments to divide the cylinder into
 */
void RenderManager::DrawDebugCylinder(const Vec4f& inLocation, const Quaternion& inRotation, const float inRadius, const float inHeight, const ColorVector& withColor, const int inSegments) 
{
	const Matrix4x4 rotMatrix = inRotation.GetRotationMatrix();
	const Vec4f xAxis = rotMatrix.GetXAxis();
	const Vec4f yAxis = rotMatrix.GetYAxis();
	const Vec4f zAxis = rotMatrix.GetZAxis();
	const float theta = 2*PI/inSegments;

	const Vec4f topCircleCenter = inLocation + (inHeight/2.f)*yAxis;
	const Vec4f bottomCircleCenter = inLocation - (inHeight/2.f)*yAxis;

	// Generate the top circle vertices
	Vec4f* topCircleVerts = new Vec4f[inSegments];
	float currTheta = 0.f;
	for(int i=0; i<inSegments; i++, currTheta+=theta)
	{
		topCircleVerts[i] = topCircleCenter + inRadius*cos(currTheta)*xAxis + inRadius*sin(currTheta)*zAxis;
	}

	// Generate the bottom circle vertices
	Vec4f* bottomCircleVerts = new Vec4f[inSegments];
	currTheta = 0.f;
	for(int i=0; i<inSegments; i++, currTheta+=theta)
	{
		bottomCircleVerts[i] = bottomCircleCenter + inRadius*cos(currTheta)*xAxis + inRadius*sin(currTheta)*zAxis;
	}

	for(int i=0; i<inSegments; i++)
	{
		DrawDebugLine(topCircleVerts[i], topCircleVerts[(i+1)%inSegments], withColor);
		DrawDebugLine(bottomCircleVerts[i], bottomCircleVerts[(i+1)%inSegments], withColor);
		DrawDebugLine(topCircleVerts[i], bottomCircleVerts[i], withColor);
	}

	delete[] topCircleVerts;
	delete[] bottomCircleVerts;
}