/*
MainControl.cpp
Written by Matthew Fisher
MainControl includes everything that changes often between applications, such as what meshes to load,
and also determines what is rendered each frame.
See the appropriate header file for a description of what this class does.
*/
//All source files include Main.h
#include "Main.h"
const int ShapeCount = 3; //the number of shapes in the shape ring
const int CutCount = 4; //the number of possible cuts
float CylinderRadius; //the radius of the cylinder's cut function
float CylinderFunction(Vec3 &V) //a global function for splitting a mesh into two regions, one where this function is negative
//(the inside of the cylinder) and another mesh that represents the region outside the cylinder.
{
return V.y * V.y + V.z * V.z - CylinderRadius * CylinderRadius;
}
float GridSize; //a paramater in the GridFunction function
float GridFunction(Vec3 &V) //same purpose as CylinderFunction, except more complicated
{
return float((int(fabsf(V.x/GridSize)) + int(fabsf(V.y/GridSize)) + int(fabsf(V.z/GridSize))) % 2 - 1);
}
void MainControl::InitShapes(GraphicsDevice &GD)
{
ShapesUnCut.Allocate(ShapeCount); //allocate room for 3 meshes
int i;
for(i=0;i<ShapeCount;i++)
ShapesUnCut[i].SetGD(GD); //associate the 3 meshes with the GD
ShapesUnCut[0].CreateSphere(1.0f, 3); //load a sphere
ShapesUnCut[1].LoadObj("feline.obj");
ShapesUnCut[2].LoadObj("bunny.obj"); //load the other two meshes from object files
for(i=0;i<ShapeCount;i++)
{
ShapesUnCut[i].CenterObject();
ShapesUnCut[i].SetRadius(1.5f); //center the shapes
}
}
void MainControl::CutShapes(GraphicsDevice &GD)
{
ShapesCut.Allocate(ShapeCount); //allocate room for 3 meshes
Mesh Out1, Out2; //when the Split function is called, we'll need 2 temporary meshes
//which represent the two output regions.
Out1.SetGD(GD); Out2.SetGD(GD); //associate these meshes with the graphics device
int i;
for(i=0;i<ShapeCount;i++)
{
ShapesCut[i].SetGD(GD); //associate the mesh with the GD
if(CutType == 0) //CutType 0 = no cut
ShapesCut[i] = ShapesUnCut[i];
if(CutType == 1) //CutType 1 = planar cut
{
Plane CutPlane;
CutPlane.LoadPointNormal(Origin,eX * 0.2f + eY); //create a simple plane
ShapesUnCut[i].PerfectSplit(CutPlane, Out1, Out2); //cut the mesh into two regions, one on
//each side of the plane.
Out2.Translate(eZ * 0.3f + eY * 0.3f); //displace one region slightly
ShapesCut[i] = Out1;
ShapesCut[i] += Out2; //combine the two regions as our output mesh
}
if(CutType == 2) //CutType 2 = cylinder cut
{
CylinderRadius = 0.35f; //the radius of the cylinder
ShapesUnCut[i].PerfectSplit(CylinderFunction, Out1, Out2); //cut the mesh as we did with the plane,
//except now we use an arbitrary function
ShapesCut[i] = Out2; //only render one side
}
if(CutType == 3) //CutType 3 = odd cut
{
GridSize = 0.25f;
ShapesUnCut[i].PerfectSplit(GridFunction, Out1, Out2); //same as the cylinder cut, except a different function
ShapesCut[i] = Out2;
}
}
//load the 3 shapes into a ring
for(i=0;i<ShapeCount;i++)
{
float Theta = i / float(ShapeCount) * 2.0f * PIf;
float Radius = 3.0f; //angle and radius around the ring
ShapesCut[i].Translate(Vec3(cosf(Theta)*Radius,sinf(Theta)*Radius,0.0f)); //translate using polar coordinates
ShapesCut[i].ColorNormals(); //apply some color
}
T.Pause();
}
void MainControl::ReInit(GraphicsDevice &GD, WindowManager &WM)
{
if(GD.GetFullScreen()) C.Mouse(0.0f); //move the mouse to the middle of the screen
MC.Perspective.PerspectiveFov(60.0f * PIf / 180.0f, //the field of view = 60 degrees
float(WM.GetWidth()) / float(WM.GetHeight()), //the aspect ratio
0.1f, //near Z-plane
20.0f); //far Z-plane
}
void MainControl::Init(GraphicsDevice &GD, WindowManager &WM)
{
ReInit(GD, WM);
//initalize the camera
C.Reset(eX*8.0f, //the eye vector
eY, //the up vector
Origin); //the vector we're looking at
MC.World.Identity(); //zero the world and view matrices
MC.View.Identity();
CutType = 1; //Start with a planar cut
InitShapes(GD); //initalize the shapes
CutShapes(GD);
TotalRotation = Vec3(1.0f, 1.0f, 1.0f); //start with some simple rotation
CurrentVariable = 2; //start by rotating around the y-axis
SecondsUntilSwitch = 3.0f; //3 seconds until we switch the axis of rotation
Time = 0.0f; //reset the time to 0
}
void MainControl::Render(GraphicsDevice &GD, WindowManager &WM)
{
Time += T.SPF(); //advance the current time
if(KeyCheckOnce(KEY_F)) GD.ToggleWireframe(); //toggle wireframe if the user presses "F"
C.WindowKeyboard(1.0f,1.0f); //move based upon the keyboard
if(GD.GetFullScreen()) C.Mouse(0.001f); //move based upon the mouse, if we're in full-screen mode
C.Update(MC, GD); //update the camera and load it into the current graphics device
SecondsUntilSwitch -= T.SPF(); //decrement seconds left until we switch
if(SecondsUntilSwitch < 0.0f) //if we should switch this frame,
{
SecondsUntilSwitch = 3.0f; //reset the switch timer
CurrentVariable = rand() % 3; //change the variable
}
if(CurrentVariable == 0) TotalRotation.x += T.SPF();
if(CurrentVariable == 1) TotalRotation.y += T.SPF();
if(CurrentVariable == 2) TotalRotation.z += T.SPF(); //based upon the variable, update the rotation vector
Matrix RotationX, RotationY, RotationZ; //the 3 rotation matrices for the ring
RotationX.RotationX(TotalRotation.x);
RotationY.RotationY(TotalRotation.y);
RotationZ.RotationZ(TotalRotation.z); //load the rotation matrices
MC.World = RotationZ * RotationX * RotationY; //load the product of the 3 matrices as the world matrix,
GD.LoadMatrix(MC); //load this new matrix set into the graphics device
int i;
for(i=0;i<ShapeCount;i++)
ShapesCut[i].Render(); //draw all the cut shapes
//update CutType based upon keyboard input
if(KeyCheckOnce(KEY_NUMPADADD))
{
CutType++;
if(CutType == CutCount) CutType = 0;
CutShapes(GD);
}
if(KeyCheckOnce(KEY_NUMPADSUBTRACT))
{
CutType--;
if(CutType < 0) CutType = CutCount - 1;
CutShapes(GD);
}
GD.DrawVector("Camera - > ", C.VecEye, 0, 20); //draw the camera position as text on the screen
GD.DrawText("Use the + or - keys on the number pad to alter the cut type.", " ", 0, 40); //help
GD.DrawNumber("Cut Type -> ", CutType, 0, 60); //draw the current cut type
}
void MainControl::FreeMemory()
{
}