/* 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() { }