/*
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 float SwirlyRadius = 1.0f; //radius of the main spiral
const float SwirlyDensity = 8.0f; //density of the rings on the main spiral
const float Epsilon = 1e-4f; //"small Delta T" used to approximate derivatives
Vec3 SwirlyFunction(float t)
{
//this is the equation of a spiral along the z-axis
return Vec3(cosf(t*SwirlyDensity)*SwirlyRadius,sinf(t*SwirlyDensity)*SwirlyRadius, t);
}
Vec3 GetCurveTangent(float t)
{
//f'(x) = (f(x+DeltaX) - f(x)) / DeltaX. We only care about the magnitude, so the DeltaX is not important
Vec3 Diff = SwirlyFunction(t + Epsilon) - SwirlyFunction(t);
Diff.Normalize();
return Diff;
}
Vec3 GetCurveNormal(float t)
{
//the normal vector is the second derivative along the curve
Vec3 Diff = GetCurveTangent(t + Epsilon) - GetCurveTangent(t);
Diff.Normalize();
return Diff;
}
void MainControl::InitCentralMesh(GraphicsDevice &GD)
{
CentralMesh.SetGD(GD); //associate the mesh with the graphics device
//this create cylinder function takes an arbitrary curve in 3-space paramaterized by a variable, say t,
//and creates a "tube" (bent cylinder) that follows the given curve from t = start to t = end.
//the radius is the radius of the cylinder. Note that the number of stacks needs to be very high
//to get a good approximation of the curve.
CentralMesh.CreateCylinder(SwirlyFunction, -4.0f, 4.0f, 0.05f, 10, 700);
CentralMesh.ColorNormals(); //add some color
}
void MainControl::ReInit(GraphicsDevice &GD, WindowManager &WM)
{
if(GD.GetFullScreen()) C[0].Mouse(0.0f); //move the mouse to the middle of the screen
MC[0].Perspective.PerspectiveFov(40.0f * PIf / 180.0f, //the field of view = 60 degrees
float(WM.GetWidth()) / float(WM.GetHeight()), //the aspect ratio
0.5f, //near Z-plane
20.0f); //far Z-plane
MC[1].Perspective.PerspectiveFov(40.0f * PIf / 180.0f, //the field of view = 60 degrees
float(WM.GetWidth()) / float(WM.GetHeight()), //the aspect ratio
0.1f, //near Z-plane
5.0f); //far Z-plane (much closer)
}
void MainControl::Init(GraphicsDevice &GD, WindowManager &WM)
{
ReInit(GD, WM);
GD.DisableWireframe();
//initalize the cameras
C[0].Reset(eX*8.0f, //the eye vector
eY, //the up vector
Origin); //the vector we're looking at
C[1].Reset(Origin, //the eye vector
eY, //the up vector
eZ); //the vector we're looking at
CurCamera = 0;
int i;
for(i=0;i<2;i++)
{
MC[i].World.Identity(); //zero the world and view matrices
MC[i].View.Identity();
}
Ind.Init(GD, 2, 15, 15); //initalize the indicator
CurvePos = -2.0f; //Starting position along the curve
InitCentralMesh(GD);
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"
MC[CurCamera].ResetWorldMatrix(); //the Indicator class changes the world matrix; reset it
C[CurCamera].WindowKeyboard(1.0f,1.0f); //move based upon the keyboard
if(GD.GetFullScreen()) C[CurCamera].Mouse(0.001f); //move based upon the mouse, if we're in full-screen mode
C[CurCamera].Update(MC[CurCamera], GD); //update the camera and load it into the current graphics device
CentralMesh.Render(); //render the spiral
int OtherCamera = (CurCamera + 1) % 2; //get the other camera's index
//this function takes a camera and draws it in another camera's frame. It will draw the viewing frustrum, eye vector
//and ortho-normal basis starting at the eye vector. The matrix controller is the frame we want to render the camera in.
//the perspective matrix is the perspective matrix of the camera we're rendering. The radius is the radius of the sphere
//at the camera's eye vector, and the length is the length of the orthonormal vectors.
Ind.DrawCamera(GD, MC[CurCamera], MC[OtherCamera].Perspective, 0.01f, 0.5f, C[OtherCamera]);
//we're going to draw the point along the curve determined by the paramaterization value CurvePos,
//and the tangent, normal, and torsion vectors at that point.
Vec3 CurveVector = SwirlyFunction(CurvePos); //the position along the curve
Vec3 CurveTangent = GetCurveTangent(CurvePos); //the tangent vector
Vec3 CurveNormal = GetCurveNormal(CurvePos); //the normal vector
Vec3 CurveTorsion;
Vec3Cross(CurveTorsion, CurveTangent, CurveNormal); //the torsion vector is the cross product of the tangent and normal vectors
CurveTorsion.Normalize();
Ind.RenderSphere(GD, MC[CurCamera], 0.1f, CurveVector, White); //render the eye vector
Ind.RenderCylinder(GD, MC[CurCamera], 0.05f, CurveVector, CurveVector + CurveTangent, Red); //render the tangent, normal, and torsion vectors
Ind.RenderCylinder(GD, MC[CurCamera], 0.05f, CurveVector, CurveVector + CurveNormal, Yellow); //centered at the point along the curve (CurveVector.)
Ind.RenderCylinder(GD, MC[CurCamera], 0.05f, CurveVector, CurveVector + CurveTorsion, Blue);
//update CurvePos based upon keyboard input
if(KeyCheck(KEY_NUMPADADD)) CurvePos += T.SPF();
if(KeyCheck(KEY_NUMPADSUBTRACT)) CurvePos -= T.SPF();
//switch between cameras if they press tab
if(KeyCheckOnce(KEY_TAB)) CurCamera = (CurCamera + 1) % 2;
if(KeyCheckOnce(KEY_P))
{
Bitmap B;
GD.CaptureScreen(WM, B); //get the screen bitmap
B.SaveBMP(keybitmap); //save it
}
/*GD.DrawVector("Camera - > ", C[CurCamera].VecEye, 0, 20); //draw the camera position as text on the screen
GD.DrawText("Use the + or - keys to change the curve position.", " ", 0, 40); //help
GD.DrawText("Press P to capture the screen to keys.bmp.", " ", 0, 60); //help
GD.DrawText("Use tab to switch cameras.", " ", 0, 80); //help
GD.DrawDouble("Curve Position -> ", CurvePos, 0, 100); //draw the current curve position
GD.DrawNumber("Camera -> ", CurCamera, 0, 120); //draw the current camera*/
}
void MainControl::FreeMemory()
{
}