Click here to Skip to main content
15,892,809 members
Articles / Programming Languages / C#

Space and Matrix Transformations - Building a 3D Engine

Rate me:
Please Sign up or sign in to vote.
4.84/5 (13 votes)
4 Sep 2009CPOL8 min read 94.9K   6.1K   101  
This Article Describes How to Navigate 3D Space
#define Debug

using System;
using System.Drawing;
using System.Collections.Generic;
using Microsoft.Samples.DirectX.UtilityToolkit;
using AGE_Engine3D;
using AGE_Engine3D.Text;
using Tao.OpenGl;
using Tao.Platform.Windows;
using AGE_Engine3D.RenderObjects;
using AGE_Engine3D.Spatial;
using AGE_Engine3D.Math;
using AGE_Engine3D.Camera;
using AGE_Engine3D.HUD;

namespace Test2_MatrixTransforms
{
    enum SimulationState 
    { 
        START,              //This Posistion the Camera Above the Table Location and shows the table
        SHOW_CUPS,          //This Shows the Cups
        MOVE_CAMERA_POS1,   //This Moves the Camera to the Front of the Table 
        SHOW_ORTHO,         //This Moves the Camera Showing the Table is Ortho
        SHOW_PERSPECTIVE,   //This Same Camera Position in Perspective
        MOVE_CAMERA_POS2,   //This Moves the Camera to the Enterence and 
        SHOW_WALLS,         //This Growz the Walls
        WALKTROUGH,         //Show the Camera walk through the Office to the Table 
        UNKOWN              //Do Nothing
    }
    class MatrixAndSpaceTransform : BaseSimulation
    {
        #region Fields

        #region MatrixAndSpaceTransform Variables
        
        private float dTime = 0;
        private float LastTime = 0;
        private List<ISpatialNode> SceneActors = new List<ISpatialNode>();
        Profiler MyProfiler;
        SimulationState MyCurrentState = SimulationState.START;
        string MyCurrentCaption = "Matrix and Space TransFormations [Press Spacebar to Begin]";
        List<string> CurrentInfo = new List<string>();
        bool IsStateLocked = false;

        SpatialBaseContainer TheOffice = null;
        float OfficeZScale = 1;
        
        SpatialBaseContainer TheTable = null;
        SpatialBaseContainer TheCups = null;
        SpatialBaseContainer TheCeiling = null;
        AGE_WalkThroughCamera MyCamera = null;
        AGE_ScreenText MyScreenText = null;
        #endregion
        #endregion

        #region Methods

        #region Constructor

        public MatrixAndSpaceTransform()
        {
            MyProfiler = new Profiler();
        }

        #endregion

        public void InitializeState()
        {
            switch (this.MyCurrentState)
            {
                case SimulationState.START:
                    #region Start State
                    this.MyCurrentCaption = "Matrix and Space Transformations [Press Spacebar to Begin]";
                    TheTable.IsVisable = true;
                    TheOffice.IsVisable = false;
                    TheCeiling.IsVisable = false;
                    TheCups.IsVisable = false;
                    this.MyCamera.MoveCameraTo(new AGE_Vector3Df(56f, 222.6852f, 6.0f),
                                               new AGE_Vector3Df(48f, 222.6852f, 3));
                    break; 
                    #endregion
                case SimulationState.SHOW_CUPS:
                    this.MyCurrentCaption = "Here is one cup with three different transforms. [Press Spacebar to Continue]";
                    #region Now we show the cups
                    TheTable.IsVisable = true;
                    TheOffice.IsVisable = false;
                    TheCeiling.IsVisable = false;
                    TheCups.IsVisable = true;
                    this.MyCamera.MoveCameraTo(new AGE_Vector3Df(56f, 222.6852f, 6.0f),
                                               new AGE_Vector3Df(48f, 222.6852f, 3));
                    break;
                    #endregion
                case SimulationState.MOVE_CAMERA_POS1:
                    #region Now we move the Camera
                    this.MyCurrentCaption = "Now we will look at Perspective. [Press Spacebar to Continue]";
                    TheTable.IsVisable = true;
                    TheOffice.IsVisable = false;
                    TheCeiling.IsVisable = false;
                    TheCups.IsVisable = true;
                    this.MyCamera.MoveCameraTo(new AGE_Vector3Df(56f, 230f, 6.0f));
                    break;
                    #endregion
                case SimulationState.SHOW_ORTHO:
                    #region Now we Show Ortho
                    this.MyCurrentCaption = "This is a Orthogonal Projection. The sides of the Table are parallel. [Press Spacebar to Continue]";
                    this.MyCamera.OrthoProject(9, SceneGraph.ScreenWidth / SceneGraph.ScreenHeight, 1.0f, 62.4338f);
                    break;
                    #endregion
                case SimulationState.SHOW_PERSPECTIVE:
                    #region Now we Show Perspective
                    this.MyCurrentCaption = "This is a Perspective Projection. The sides of the Table are not parallel. [Press Spacebar to Continue]";
                    this.MyCamera.Project(50.0f, SceneGraph.ScreenWidth / SceneGraph.ScreenHeight, 1.0f, 62.4338f);
                    break;
                    #endregion
                case SimulationState.MOVE_CAMERA_POS2:
                    #region Now we move the Camera to the Enterance
                    this.MyCurrentCaption = "Now we will move to the Office Entrance using a Translation Transform. [Press Spacebar to Continue]";
                    TheTable.IsVisable = true;
                    TheOffice.IsVisable = false;
                    TheCups.IsVisable = true;
                    this.MyCamera.MoveCameraTo(new AGE_Vector3Df(95.7719f, 229.9174f,6.0000f),
                                               new AGE_Vector3Df(48f, 222.6852f, 3),
                                               1);
                    break;
                    #endregion
                case SimulationState.SHOW_WALLS:
                    #region Now we move the Camera to the Enterance
                    this.MyCurrentCaption = "The wall appear using a Scaling Transform. [Press Spacebar to Continue]";
                    TheTable.IsVisable = true;
                    TheOffice.IsVisable = true;
                    TheCups.IsVisable = true;
                    this.MyCamera.MoveCameraTo(new AGE_Vector3Df(95.7719f, 229.9174f, 6.0000f),
                                               new AGE_Vector3Df(48f, 222.6852f, 3));
                    this.OfficeZScale = 0.000001f;
                    break;
                    #endregion
                case SimulationState.WALKTROUGH:
                    #region Now we move the Camera to the Enterance
                    this.MyCurrentCaption = "This is a walkthrough uses a series of Camera Translations. [Press Spacebar to Start Over]";
                    TheTable.IsVisable = true;
                    TheOffice.IsVisable = true;
                    TheCups.IsVisable = true;
                    this.MyCamera.UsePath("Path1.txt", 3);
                    break;
                    #endregion
                default:
                    break;
            }
        }

        #region Overidden Functions
        
        override public void UpdateScene()
        {
            float tmpTime = (float)DXTimer.GetTime();
            this.dTime = tmpTime - this.LastTime;
            this.LastTime = tmpTime;
            this.MyCamera.Update(this.dTime);
            #region Update when I am Showing Walls
            if (this.MyCurrentState == SimulationState.SHOW_WALLS)
            {
                if (this.OfficeZScale < 1)
                {
                    
                    this.OfficeZScale += this.dTime;
                    if (this.OfficeZScale > 1)
                    {
                        this.OfficeZScale = 1;
                        this.TheCeiling.IsVisable = true;
                    }
                    TheOffice.Reset_Default();
                    TheOffice.NewScale(new AGE_Vector3Df(1, 1, this.OfficeZScale));
                }             
            } 
            #endregion
            #region Update the Paths during My Walkthrough
            if (this.MyCurrentState == SimulationState.WALKTROUGH)
            {
                if (this.MyCamera.CurrentPath != null)
                {
                    if (!this.MyCamera.CurrentPath.IsActive && this.MyCamera.CurrentPath.MyName == "Path1.txt")
                        this.MyCamera.UsePath("Path2.txt", 4);
                }
            } 
            #endregion

            this.CurrentInfo.Clear();
            this.CurrentInfo.Add(this.MyCurrentCaption);
            this.CurrentInfo.Add("Frames Per Second :" + this.FrameRate);
            this.MyScreenText.AddText(this.CurrentInfo, new AGE_Vector3Df(0, 0, 0));
        }

        override public void UpdateInput()
        {
            if ((this.Keys[32] && !this.IsStateLocked) || (this.Keys[32] && this.Keys[16]))
            {
                this.MyCurrentState++;
                this.Keys[32] = false;
                if (this.MyCurrentState == SimulationState.UNKOWN)
                    this.MyCurrentState = SimulationState.START;
#if Debug
                Console.WriteLine(this.MyCurrentState.ToString());
#endif
                this.InitializeState();
            }
            if (this.Keys[13])
            {
                this.InitializeState();
            }
        }
        
        override public void DrawGLScene()
        {
            SceneGraph.RenderScence();
            this.SwapBuffer = true; //This is the flag that tells the calling ViewWindow update the dispaly
        }
        
        override public void ProcessStep()
        {
            if (!this.IsInitialize)
            {
                //Initialize the Simulation a derived function
                this.InitializeSimulation();
            }

            if (this.Active && this.IsInitialize)
            {

                /*--------------------------------------------------------------------------------  
                 * This is how I am currently structuring the each call to the ProcessStep method.
                 *   1.	I update the application with user inputs   //	this.UpdateInput();
                 *   2.	Then, I update the Scene info.              //	this.UpdateScene();
                 *   3.	Finally,  Draw the scene.                   //	this.DrawGLScene(); 
                 *------------------------------------------------------------------------------*/
                this.UpdateInput();
                this.UpdateScene();
                this.SwapBuffer = false;
                if (this.OpenGLFlag)
                {

                    this.DrawGLScene();
                    this.FrameRate = DXTimer.CalculateFrameRate();
                }

            }

        }

        override public void InitializeSimulation()
        {
            base.InitializeSimulation();
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.25f);                           // Black Background
            #region Load Resources
            SceneGraph.WorldObjectList.Clear();
            SceneGraph.HUDObjects.Clear();
            #region Creat Actors
            if (ResourceManager.LoadMeshResouse("OfficeV2.obj"))
            {
                TheOffice = new SpatialBaseContainer();
                TheOffice.Geometry = ResourceManager.GetMeshObject("OfficeV2.obj");
                this.SceneActors.Add(TheOffice);
                TheOffice.IsVisable = false;
            }
            if (ResourceManager.LoadMeshResouse("Ceiling.obj"))
            {
                TheCeiling = new SpatialBaseContainer();
                TheCeiling.Geometry = ResourceManager.GetMeshObject("Ceiling.obj");
                this.SceneActors.Add(TheCeiling);
                TheOffice.IsVisable = false;
            }
            if (ResourceManager.LoadMeshResouse("Table.obj"))
            {
                TheTable = new SpatialBaseContainer();
                TheTable.Geometry = ResourceManager.GetMeshObject("Table.obj");
                this.SceneActors.Add(TheTable);
                TheTable.NowRotate(0, 0, AGE_Engine3D.Math.AGE_Functions.PI / 2);
                TheTable.NowMove(new AGE_Vector3Df(48.1973f, 222.4320f, 0f));
                
            }
            if (ResourceManager.LoadMeshResouse("Glass.obj"))
            {
                TheCups = new SpatialBaseContainer();
                TheCups.Geometry = ResourceManager.GetMeshObject("Glass.obj");
                TheCups.NowMove(new AGE_Vector3Df(0.0f, 0.0f, 3.083f));
                this.TheTable.AddChildren(TheCups);
                //Child Cup #1
                SpatialBaseContainer NewKid = new SpatialBaseContainer();
                NewKid.Geometry = TheCups.Geometry;
                NewKid.NowScale(new AGE_Vector3Df(1.0f, 0.75f, 2));
                NewKid.NowMove(new AGE_Vector3Df( 3f,0, 0));
                TheCups.AddChildren(NewKid);
                //Child Cup #2
                NewKid = new SpatialBaseContainer();
                NewKid.Geometry = TheCups.Geometry;
                NewKid.NowScale(new AGE_Vector3Df(1.0f, 3.0f, .5f));
                NewKid.NowMove(new AGE_Vector3Df(-3f,0, 0));
                TheCups.AddChildren(NewKid);

                this.MyScreenText = new AGE_ScreenText();
                SceneGraph.HUDObjects.Add(this.MyScreenText);
                this.MyScreenText.CreatMatrixTransform();
            }
            #endregion

            #region Simulation Default Camera
            AGE_Vector3Df Pos = new AGE_Vector3Df(95.7719f, 229.9174f, 5.0f);
            AGE_Vector3Df Target = new AGE_Vector3Df(34.4021f, 218.4397f, 3.0f);
            AGE_Vector3Df Dir = Target - Pos;
            Dir = Dir.UnitVector();
            this.MyCamera = new AGE_WalkThroughCamera("Start Camera",
                                                      Pos,
                                                      Target,
                                                      new AGE_Vector3Df(0, 0, 1));
            this.MyCamera.Project(50.0f, SceneGraph.ScreenWidth / SceneGraph.ScreenHeight, 1.0f, 62.4338f);
            MyCamera.LoadPath("Path1.txt");
            MyCamera.LoadPath("Path2.txt");
            SceneGraph.CurrentCamera = MyCamera;
            
            #endregion
            SceneGraph.WorldObjectList = this.SceneActors;
            #endregion
            
            #region Lighting
            SceneGraph.RenderLights = true;
            Gl.glEnable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_LIGHT0);


            float[] AmbentLight = new float[4] { 0.2f, 0.2f, 0.2f, 1 };
            float[] DiffuseLight = new float[4] { 0.8f, 0.8f, 0.8f, 1 };
            //float[] DiffuseLight = new float[4] { 1, 1, 1, 1 };
            float[] SpecLight = new float[4] { 0.5f, 0.5f, 0.5f, 1 };

            Gl.glLightModelfv(Gl.GL_LIGHT_MODEL_AMBIENT, AmbentLight);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, AmbentLight);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, DiffuseLight);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, SpecLight);

            float[] TPos = new float[4] { 100, 230, 5.0f, 1 };
            float[] TDir = new float[4] { Dir.X, Dir.Y, Dir.Z, 1 };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, TPos);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPOT_DIRECTION, TDir); 
            #endregion

            this.MyCurrentState = SimulationState.START;
            this.InitializeState();
        }

        #endregion
        
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer Lea+Elliott, Inc.
United States United States
I am a licensed Electrical Engineer at Lea+Elliott, Inc. We specialize in the planning, procurement and implementation of transportation systems, with special emphasis on automated and emerging technologies.

Comments and Discussions