gr_tut7_screenshot.jpg

JointsAndScenegraph.cs

#region Using directives

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using Microsoft.DirectX.Direct3D;

using JadEngine;
using JadEngine.Video;
using JadEngine.Core;
using JadEngine.Mathematics;
using JadEngine.Scene;
using JadEngine.Scene.MD5;
using JadEngine.Physics;
using JadEngine.Particles;
using JadEngine.Sound;
using JadEngine.Tools;
using JadEngine.Import;
using JadEngine.Input;

#endregion

namespace Tutorial
{
    /// <summary>
    /// This example will teach you to create joints between physic objects and
	/// to associate nodes to another node so these nodes together.
	/// The tutorial uses the default first-person camera of the engine. Use keys WASD
	/// and the mouse to control it.
    /// </summary>
	public class JointsAndScenegraph : JApplication
    {
        #region Structs

        /// <summary>
		/// Keeps the necessary information of the chain to be able to create
		/// the joint that joins it with the lamp
        /// </summary>
        struct chain
        {
			/// <summary>
			/// TODO
			/// </summary>
            public Vector3 finalPos;

			/// <summary>
			/// TODO
			/// </summary>
            public JRigidBody linkBody;
        }

        #endregion

        #region Fields

		/// <summary>
		/// Indicates if the help must be shown in the screen or not
		/// </summary>
        bool showHelp = true;

        /// <summary>
		/// Left chain
		/// </summary>
        chain leftChain;

		/// <summary>
		/// Right chain
		/// </summary>
		chain rightChain;

        /// <summary>
		/// Body that represents the lamp
		/// </summary>
        JRigidBody lampBody;

        /// <summary>
		/// Link JMeshObject
		/// </summary>
        JMeshObject linkMeshObject;

        /// <summary
		/// >Lamp JMeshObject
		/// </summary>
        JMeshObject lamp;

        #endregion

		#region Methods

		/// <summary>
		/// The engine calls this method after creating the device
		/// </summary>
		/// <param name="form">Form used as window</param>
		/// <returns>True if everything went right</returns>
		public override bool InitGame(Form form)
		{
			// Create the fonts and texture objects
			Jad.AfterCreateDevice();

			// Load default textures, scenes, shaders,...
			Jad.LoadCreateInHouse();

            #region Objects

            // Activate Newton physics
            Jad.Physics.Create();

            // Create the scene
            CreateScene();

            #endregion

            #region Light associated with the lamp

			// Create a spot light that will be associated with the lamp,
			// so when the lamp moves, the light will move with it

            JSpotLight spotLight = (JSpotLight)Jad.Scene.Lights.Create("spot", JLightType.Spot);

			// Set its position, in this example as the light is associated with the lamp,
			// the vector is a relative position to the lamp
            spotLight.Transform.Position = new Vector3(0, 0, 0.4f);

			// By default, it is created looking at the Z axis. We want that light
			// goes down, so we rotate it in the X axis
            spotLight.Transform.Angles = new Vector3(Geometry.DegreeToRadian(90f),0,0);

            // Intensity
            spotLight.Multiplier = 1f;

            // Attenuation
            spotLight.Attenuation.Type = JLightAttenuationType.DualRadius;

			// Distance to start attenuating the light
			spotLight.Attenuation.Start = 5f;

			// Distance where the light is completely attenuated
			spotLight.Attenuation.End = 9f;

            // Color
            spotLight.Color = JColor.RedColor;

			// The light affect the diffuse component of the material
            spotLight.AffectDiffuse = true;

			// The light affect the specular component of the material
            spotLight.AffectSpecular = true;

			// We don´t generate shadows
            spotLight.CastShadows = false;

			// Cone aperture of the spot light
            spotLight.HotSpot = 25f;

			// Maximum cone aperture
            spotLight.FallOff = 50f;

            // Attach the light to the lamp
			spotLight.SceneGraph.Attach(lamp);

			// Put ambient light
            Jad.Scene.Lights.Ambient = new JColor(0.3f, 0.3f, 0.3f);

            #endregion

            Jad.Scene.Camera.Transform.Position = new Vector3(0, 1f, -6f);

			// Everything is set, start the engine
			Jad.Begin();

			// Create input class to manage the keyboard and the mouse
			Jad.CreateInput();

			return true;
		}

		/// <summary>
		/// Creates the scene of the tutorial
		/// </summary>
		void CreateScene()
		{
			// Load the link. We need to scalate it also
			float scale = 1f / 50f;

			Jad.Import.Load("link.haddd", scale);

			// We access the first element of the objects we have just loaded
			linkMeshObject = Jad.Import.MeshObjects[0];

			// Build the left chain
			BuildChain(new Vector3(-0.5f, 4.0f, 0.0f), ref leftChain, "l");

			// Build the right chain
			BuildChain(new Vector3(0.5f, 4.0f, 0.0f), ref rightChain, "r");

			// Hide the loaded link, as we have created the chains and this link
			// is useless now
			linkMeshObject.Hide = true;

			// Create the lamp
			CreateLamp();

			// Create a room to put the lamp
			CreateRoom();
		}

		/// <summary>
		/// Creates the room
		/// </summary>
        void CreateRoom()
        {
            JMesh cubeMesh = JMesh.CreateCube(7f,7f, 7f);

			// Invert the cube faces, as we want to be inside the room
			cubeMesh.IndexBuffer.InvertFaces();

            JMeshObject cube = Jad.Scene.MeshObjects.Create("room", false);

            // Associate the mesh with the meshobject
            cube.Mesh = cubeMesh;

            // Create a materials array of 1 element
            JMaterial[] material = new JMaterial[1];

			material[0] = Jad.Scene.Materials.Create();

            // Create the layer
            JMaterialLayer layer = new JMaterialLayer();

            // Add it to the material
            material[0].AddLayer(layer);

            layer.DiffuseMap.Texture = Jad.Video.Textures.Create2D("brick_d", true);

			// Modify the material tiling so it repeats more times the texture
            layer.DiffuseMap.UTile = layer.DiffuseMap.VTile = 4f;

            // Set the material we have just created to our JMeshObject
            cube.Material = material;
        }

		/// <summary>
		/// Builds the chain from the ceil of the room to the lamp
		/// </summary>
		/// <param name="pos">TODO</param>
		/// <param name="chain">TODO</param>
		/// <param name="prefix">TODO</param>
        void BuildChain(Vector3 pos,ref chain chain, string prefix)
        {
            JRigidBody parent = null;

            float linkHeight = linkMeshObject.Bounding.BoundingBox.Height;

            JCollision colision = new JCollision();

			// Create a collision object. It´ll have the same size of the link.
			// We use a sphere to represent it, although it´s not the best type for this

			colision.CreateSphere(linkMeshObject.Bounding.BoundingBox.Width / 2f, linkHeight / 2f, linkMeshObject.Bounding.BoundingBox.Depth / 2f);

            float rotacionY = 0;

            for (int i = 0; i < 10; i++)
            {
				// Clone the original link, giving it a new name
                JMeshObject mesh = linkMeshObject.Clone("link" + prefix + i.ToString());

				// Set the position of the new JMeshObject
                mesh.Transform.Position = pos;

				// Create a RigidBody
                JRigidBody body = Jad.Physics.RigidBodies.Create(colision, mesh);

				// Give it mass and inertia
                body.SetMassMatrix(5f, 1f, 3f, 0.5f);

				// Create the body matrix
                Matrix m = Matrix.RotationY(rotacionY) * Matrix.Translation(pos);

                body.Matrix=m;

				// Create a new joint of Ball and Socket type
                JBallJoint joint;

                joint = new JBallJoint(
					pos + new Vector3(0, linkHeight / 2, 0),  // Indicate the position where contact is established in WORLD COORDINATES
                    new Vector3(0, 1f, 0),  // Rotation axis
                    Geometry.DegreeToRadian(0), // Allow total rotation
                    0,      // Allow total rotation
                    body,   // The rigid body is associated to this joint
                    parent  // The parent of this joint
                    );

				// In the next join, this will be the parent
                parent = body;

				// Move down a little the link, but not completely so it gives the impression it´s linked

                pos.Y -= linkHeight * 0.8f;

				// The links alternate their rotation so they seem a chain
                if (rotacionY == 0)
                    rotacionY = Geometry.DegreeToRadian(90f);
                else
                    rotacionY = 0f;

				// Save the values to create later the lamp joints

                chain.linkBody = body;

                chain.finalPos = pos + new Vector3(0, linkHeight / 2, 0);
            }

            colision.Release();
        }

		/// <summary>
		/// Creates the lamp
		/// </summary>
        void CreateLamp()
        {
			// Create a cube to do as lamp

            Vector3 size = new Vector3(2f, 0.4f, 1f);

            JMesh mesh = JMesh.CreateCube(size);

            lamp = Jad.Scene.MeshObjects.Create("lamp", false);

			// Associate the mesh with the meshobject

            lamp.Mesh = mesh;

			// Create a materials array of 1 element
            JMaterial[] material = new JMaterial[1];

			material[0] = Jad.Scene.Materials.Create();

			// Create the layer
            JMaterialLayer layer = new JMaterialLayer();

			// Add it to the material
            material[0].AddLayer(layer);

            layer.DiffuseMap.Texture = Jad.Video.Textures.Create2D("Pared_Difusse", true);

            // Asignamos a nuestros JMeshObject el materal que acabamos de crear
            lamp.Material = material;

			// In Newton, we must define first a "colisionable" object setting the
			// shape of the object

            JCollision collision=new JCollision();

			// It´ll have the same size as the one done to create the mesh
			// BECAUSE IN NEWTON, AS IN HADDD, THE DISTANCE MEASURE UNIT IS THE METER

            collision.CreateBox(ref size);

			// Create a Rigid body. Rigid bodies are the objects that have
			// the colision and physic properties set. We associate the collision
			// object we just created with the JMeshObject
            JRigidBody body = Jad.Physics.RigidBodies.Create(collision, lamp);

			// Set the mass and inertia
            body.SetMassMatrix(50f, 2f, 0.4f, 1f);

			// We need to set a matrix. We don´t use the same as in the meshobject
			// because we can have rigid bodies that ARE NOT associated with a mesh,
			// and because of that we have to set a matrix instead of using the one
			// of JMeshObject

            Vector3 pos = leftChain.finalPos;
            pos.X=(rightChain.finalPos.X+leftChain.finalPos.X)/2f;
			pos.Y -= linkMeshObject.Bounding.BoundingBox.Height / 2f;

            Matrix matrix = Matrix.Translation(pos);

            body.Matrix=matrix;

			// Release the collision as we won´t use it anymore
            collision.Release();

            lampBody = body;

			// Add the joints
            JBallJoint joint = new JBallJoint(leftChain.finalPos, new Vector3(0, 1f, 0), 0, 0, body, leftChain.linkBody);
            JBallJoint joint2 = new JBallJoint(rightChain.finalPos, new Vector3(0, 1f, 0), 0, 0, body, rightChain.linkBody);
        }

		/// <summary>
		/// This method is called every frame and it´s where the input
		/// events and the game action must be placed
		/// </summary>
		/// <returns>True to continue, false to exit the application</returns>
		public override bool Update()
		{
			// Exit the app?
			if (Jad.Input.Keyboard[Key.Escape].Down) return false;

			if (Jad.Input.Keyboard[Key.F1].Pressed) showHelp = !showHelp;

            // If G key was pressed we activate / deactivate the gizmos
			// The diference between KeyTouch and KeyPressed is that KeyTouch only returns
			// true if the key was pressed for the first time and not when it´s down as in
			// KeyPressed

			// KeyTouch is like normal writting, returning true only once for every key press

			if (Jad.Input.Keyboard[Key.G].Pressed)
				Jad.Scene.ShowGizmos = !Jad.Scene.ShowGizmos;

			// If they P key was pressed you can see / hide Newton collision objects
			if (Jad.Input.Keyboard[Key.P].Pressed)
				Jad.Physics.Debug = !Jad.Physics.Debug;

			// If the I key was pressed we add impulse to the sphere
			if (Jad.Input.Keyboard[Key.I].Pressed)
				lampBody.AddImpulse(new Vector3(0, 0, 3f));

			// Everything was right, continue
			return true;
		}

		/// <summary>
		/// Render method
		/// </summary>
		public override void Render()
		{
            JView backbuffer = Jad.Video.Views[0];

            // Render the Jad.Scene using the scene camera
            backbuffer.Render();

            if (showHelp)
            {
                // Get access to the 1st font. The engine creates a font by default
                JFont font = Jad.Video.Fonts[0];

                // Start fonts rendering
                Jad.Video.Fonts.Begin();

                // Write text in the first line, position x=0, yellow color
                font.RenderLine(Jad.Version + ". Press ESC to exit. Press G to Show/Hide Gizmos. F1 show/hide text", 0, JColor.Yellow);

                // Write text in the second line, position x=0, white color
                font.RenderLine(Jad.Video.Views.CurrentView.Stats.Fps + " FPS", 0, JColor.White);

                font.RenderLine("Press P to show Physic collisions", 0, JColor.Yellow);

                font.RenderLine("Press I to add impulse", 0, JColor.Yellow);

                // End fonts rendering
                Jad.Video.Fonts.End();
            }

            // Show the backbuffer
            backbuffer.Present();
        }

		#endregion
    }
}

Last edited Mar 8, 2007 at 12:17 PM by Vicente, version 5

Comments

No comments yet.