gr_tut20_screenshot.jpg

JTutorial20.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 Microsoft.DirectX.DirectInput;
		
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;
		
#endregion
		
namespace Tutorial
{
	/// <sumary>
	/// This example will teach you to create materials and assign them elastic properties.
	/// Each time you hit a hinge, it loses 1 hit point. When it gets to 0, the joint is destroyed
	/// and the hinge falls down. The red hinge has angle's limits.
	/// </sumary>
	public class JTutorial : JApplication
	{
		#region Structs
		
		/// <summary>
		/// TODO
		/// </summary>
		struct Contact
		{
			#region Fields
		
			/// <summary>
			/// TODO
			/// </summary>
			public JRigidBody Body0;
		
			/// <summary>
			/// TODO
			/// </summary>
			public JRigidBody Body1;
		
			#endregion
		};
		
		#endregion
		
		#region Fields
		
		/// <summary>
		/// Indicates if the help must be shown in the screen or not
		/// </summary>
		bool showHelp = true;
		
		/// <summary>
		/// TODO
		/// </summary>
		JMesh mesh;
		
		/// <summary>
		/// TODO
		/// </summary>
		JCollision collision;
		
		/// <summary>
		/// Elastic material
		/// </summary>
		JPhysicsMaterial elastic;
		
		/// <summary>
		/// Non-elastic material
		/// </summary>
		JPhysicsMaterial nonElastic;
		
		/// <summary>
		/// TODO
		/// </summary>
		JSample sample;
		
		/// <summary>
		/// TODO
		/// </summary>
		Contact contactValues;
		
		/// <summary>
		/// TODO
		/// </summary>
		MaterialSetCollisionBegin mscbCB;
		
		/// <summary>
		/// TODO
		/// </summary>
		MaterialSetCollisionProcess mscpCB;
		
		/// <summary>
		/// TODO
		/// </summary>
		MaterialSetCollisionEnd msceCB;
		
		#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 Creation of the world
		
			// Activate Newton's physics system
			Jad.Physics.Create();
		
			CreateGround();
		
			CreateHinges();
		
			CreateSphereMeshAndMaterials();
		
			BuildMaterialCollision();
		
			#endregion
		
			// Create the sound, setting the sound priority and quality (for 3D sound)
			Jad.CreateSound(CooperativeLevel.Priority, JSoundQuality.High);
		
			// Create the 2D sample
			sample = Jad.Sound.Create("golpe");
		
			// Put ambient light
			Jad.Scene.Lights.Ambient = new JColor(0.6f);
		
			Jad.Scene.Camera.Position = new Vector3(0, 1f, -6f);
		
			Jad.Scene.Camera.FarPlane = 50F;
		
			// When working with physics the best is set a fixed time
			Jad.Timer.FixedMode = true;
			Jad.Timer.FixedModeFPS = 1.0f / 60.0f;	// 60 fps
		
			// Set our skybox
			Jad.Scene.SkyBox = new JSkyBox("lobbycube");
		
			// Everything is set, start the engine
			Jad.Begin();
		
			// Enable bloom effect
			Jad.Scene.BloomEffect.Enabled = true;
			Jad.Scene.BloomEffect.HighPass.HighPassValue = 0.6f;
			Jad.Scene.BloomEffect.HighPass.Multiplier = 0.7f;
		
			// Create input class to manage the keyboard and the mouse
			Jad.CreateInput();
		
			return true;
		}
		
		/// <summary>
		/// This callback is called when the two aabb boxes of the collisiong object overlap
		/// </summary>
		/// <param name="material">TODO</param>
		/// <param name="body0">TODO</param>
		/// <param name="body1">TODO</param>
		/// <returns>TODO</returns>
		int GenericContactBegin(int material, int body0, int body1)
		{
		
			contactValues.Body0 = (JRigidBody)JNewtonWrapper.BodyGetUserData(body0);
			contactValues.Body1 = (JRigidBody)JNewtonWrapper.BodyGetUserData(body1);
		
			// Return one the tell Newton the application wants to proccess this contact
			return 1;
		}
		
		/// <summary>
		/// This callback is called for every contact between the two bodies
		/// </summary>
		/// <param name="material">TODO</param>
		/// <param name="contact">TODO</param>
		/// <returns>TODO</returns>
		int GenericContactProcess(int material, int contact)
		{
			Object userData = (Object)JNewtonWrapper.MaterialGetMaterialPairUserData(material);
		
			if (contactValues.Body0.Node != null && contactValues.Body1.Node != null)
			{
				MyMeshObject hinge = null;
		
				if (contactValues.Body0.Node is MyMeshObject) hinge = (MyMeshObject)contactValues.Body0.Node;
				if (contactValues.Body1.Node is MyMeshObject) hinge = (MyMeshObject)contactValues.Body1.Node;
		
				if (hinge != null)
				{
					if (hinge.Hits > 0)
					{
		
						JColor color = hinge.Material[0].Layers[0].DiffuseMap.Color;
		
						// Set the object a little darker
		
						hinge.Material[0].Layers[0].DiffuseMap.Color -= 0.1f;
		
						color -= 0.1f;
		
						//hinge.Material[0].Layers[0].DiffuseMap.Color = color;
		
						// Play the hit sound
						sample.Play(false);
		
						// If we hit a lot, destroy the joint, and the piece will fall down
						if (--hinge.Hits <= 0)
							hinge.Physics.RigidBody.Joint.Destroy();
					}
				}
			}
		
			return 1;
		}
		
		/// <summary>
		/// This function is called after all contacts for these pairs are proccesed
		/// </summary>
		/// <param name="material">TODO</param>
		void GenericContactEnd(int material)
		{
		}
		
		/// <summary>
		/// TODO
		/// </summary>
		void BuildMaterialCollision()
		{
			mscbCB = new MaterialSetCollisionBegin(GenericContactBegin);
			mscpCB = new MaterialSetCollisionProcess(GenericContactProcess);
			msceCB = new MaterialSetCollisionEnd(GenericContactEnd);
		
			// We set the collision between the pair of materials that are interesting for us
		
			JPhysicsMaterial.SetCollisionDelegate(Jad.Physics.DefaultPhysicsMaterial, elastic, null, mscbCB, mscpCB, msceCB);
			JPhysicsMaterial.SetCollisionDelegate(Jad.Physics.DefaultPhysicsMaterial, nonElastic, null, mscbCB, mscpCB, msceCB);
		}
		
		/// <summary>
		/// Creates the ground
		/// </summary>
		void CreateGround()
		{
			// Create a rectangle to use as a floor
			JMesh groundMesh = JMesh.CreateRectangle(30f, 30f, 50, 50, JCreateRectangle.XZ, false, 1f, 1f);
		
			// Add it some noise ...
			float noise = 0.5f;
		
			groundMesh.Noise(new Vector3(0, noise, 0));
		
			JMeshObject ground = Jad.Scene.MeshObjects.Create("ground", false);
		
			// Now associate the mesh with the meshobject
			ground.Mesh = groundMesh;
		
			// 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);
		
			// Set the material we have just created to our ground
			ground.Material = material;
		
			// Now we build the collision tree. This case is formed only by the floor
		
			List<JMeshObject> meshesForTree = new List<JMeshObject>();
		
			meshesForTree.Add(ground);
		
			// Build the collision tree from the list
			JRigidBody body = Jad.Physics.BuildCollisionTree(meshesForTree, false);
		}
		
		/// <summary>
		/// Creates the hinges
		/// </summary>
		void CreateHinges()
		{
			int i = 0;
		
			for (int x = 0; x < 5; x++)
				for (int y = 0; y < 5; y++)
				{
					float px = (float)x * 1.5f;
					float py = 1 + (float)y * 1.5f;
		
					CreateHinge(new Vector3(px, py, 0), i);
		
					i++;
		
					if (i > 2) i = 0;
				}
		}
		
		/// <summary>
		/// Creates a hinge
		/// </summary>
		/// <param name="position">Position of the hinge</param>
		/// <param name="hingeType">Hinge type</param>
		void CreateHinge(Vector3 position, int hingeType)
		{
			Vector3 size = new Vector3(1, 1, 0.1f);
		
			JMesh mesh = JMesh.CreateCube(size);
		
			// Crete my own meshobject
		
			MyMeshObject meshObject = new MyMeshObject("hinge");
		
			// Add it to the scene graph, and the list
		
			Jad.Scene.MeshObjects.AddMeshObject(meshObject);
		
			// Now associate the mesh with the meshobject
		
			meshObject.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("wood", true);
		
			// Set the material we have just created to our ground
			meshObject.Material = material;
		
			JCollision collision = new JCollision();
		
			collision.CreateBox(ref size);
		
			// The inertia values are very important for realistic physics.
			// Newton can compute now the inertia values for you.
			// If you do not compute inertia, the engine use the default
			// values of 1,1,1
		
			collision.ComputeInertia();
		
			JRigidBody body = Jad.Physics.RigidBodies.Create(collision, meshObject);
		
			body.Mass = 1f;
		
			Matrix matrix = Matrix.Translation(position);
		
			body.Matrix = matrix;
		
			// We change the pivot point and the diffuse color to have different hinges
		
			if (hingeType == 1)
			{
				position.Y += size.Y / 2;
				layer.DiffuseMap.Color = JColor.RedColor;
			}
		
			if (hingeType == 2)
			{
				position.Y -= size.Y / 2;
				layer.DiffuseMap.Color = JColor.BlueColor;
			}
		
			JHingeJoint joint = new JHingeJoint(position, new Vector3(1, 0, 0), body, null);
		
			// Set limits to the hinge joints when the pivot point
			// is up
			if (hingeType == 1)
			{
				// Set the angle limit when the hinge goes back
				joint.MinAngleLimit = Geometry.DegreeToRadian(80);
				// Set the angle limit when the hinge goes front
				joint.MaxAngleLimit = Geometry.DegreeToRadian(45);
		
				joint.UseAngleLimit = true;
			}
		}
		
		/// <summary>
		/// TODO
		/// </summary>
		void CreateSphereMeshAndMaterials()
		{
			float radius = 0.25f;
		
			mesh = JMesh.CreateSphere(radius, 20, 20);
		
			// In Newton, we must define first a "colisionable" object setting the
			// shape of the object.
			// As the collision object is the same for all the object, we create it here
			// and reuse it
		
			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.CreateSphere(radius, radius, radius);
		
			// Create a material with high elasticity
		
			elastic = new JPhysicsMaterial();
		
			// Set the Elasticity between the default material ( used for the ground )
			// and the elastic material
			elastic.SetDefaultElasticity(Jad.Physics.DefaultPhysicsMaterial.Material, 0.95f);
		
			// Now a non so elastic material
			nonElastic = new JPhysicsMaterial();
			nonElastic.SetDefaultElasticity(Jad.Physics.DefaultPhysicsMaterial.Material, 0.1f);
		
			// Set the tunneling values. See above for an explanation of tunneling
					Jad.Physics.DefaultPhysicsMaterial.SetContinuousCollisionMode(elastic.Material, JContinuousCollisionMode.TakeCareWithTunneling);
			Jad.Physics.DefaultPhysicsMaterial.SetContinuousCollisionMode(nonElastic.Material, JContinuousCollisionMode.TakeCareWithTunneling);
		}
		
		/// <summary>
		/// Adds a sphere to the scene
		/// </summary>
		/// <param name="useElasticMaterial">Indicates if the spehre uses the elastic material or not</param>
		void AddSphere(bool useElasticMaterial)
		{
			// Put the cubes so that they are stacked and centered
			Vector3 pos = Jad.Scene.Camera.Position;
		
			string name;
		
			if (useElasticMaterial) name = "elastic"; else name = "non elastic";
		
			JMeshObject meshObject = Jad.Scene.MeshObjects.Create(name, false);
		
			// Associate the mesh with the meshobject
		
			meshObject.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);
		
			// Set the material we have just created to our JMeshObject
			meshObject.Material = material;
		
			// 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, meshObject);
		
			// Set the mass
			body.Mass = 2f;
		
			// Tunnelling is the effect that happens, for example, when a bullet hits a wall.
			// The bullet has a very high velocity, so in a frame he hasn´t hit the wall yet, but in the next one, he has gone through it, so no collision is detected. 
			// Version 1.51 of Newton can handle automatically this type of things.
			// Note: You must set the coontinous mode to the pair of materials too
		
			body.ContinuousCollisionMode = JContinuousCollisionMode.TakeCareWithTunneling;
		
			if (useElasticMaterial)
			{
				body.SetMaterialGroupID(elastic.Material);
				layer.DiffuseMap.Color = JColor.Yellow;
			}
		
			else
			{
				body.SetMaterialGroupID(nonElastic.Material);
				layer.DiffuseMap.Color = JColor.GreenColor;
			}
		
			Matrix matrix = Matrix.Translation(pos);

			body.Matrix = matrix;
		
			// Add impulse using the look vector
			body.AddImpulse(Jad.Scene.Camera.Look * 10f);
		}
		
		/// <summary>
		/// Release the objects
		/// </summary>
		public override void End()
		{
			collision.Release();
		}
		
		/// <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 Action()
		{
			// Exit the app?
			if (Jad.Input.Keyboard.KeyPressed(Key.Escape)) return false;
		
			if (Jad.Input.Keyboard.KeyTouch(Key.F1)) 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.KeyTouch(Key.G))
				Jad.Scene.ShowGizmos = !Jad.Scene.ShowGizmos;
		
			// If they P key was pressed you can see / hide Newton collision objects
			if (Jad.Input.Keyboard.KeyTouch(Key.P))
				Jad.Physics.Debug = !Jad.Physics.Debug;
		
			if (Jad.Input.Keyboard.KeyTouch(Key.Space))
				AddSphere(true);
		
			if (Jad.Input.Keyboard.KeyTouch(Key.Return))
				AddSphere(false);
		
			// Everything was right, continue
			return true;
		}
		
		/// <summary>
		/// Render method
		/// </summary>
		public override void Render()
		{
			// Prepare the scene to start the render
			Jad.Scene.Begin();
		
			// Render all the scene objects
			Jad.Scene.Render();
		
			// Do the post-production
			Jad.Scene.ProcessPostProduction();
		
			// Render various things of the scene (gizmos, axes, names,...)
			Jad.Scene.RenderMiscellaneous();
		
			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();
		
				RenderHits(font);
		
				// 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.Render.Stats.Fps + " FPS", 0, JColor.White);
		
				font.RenderLine("Press P to show Physic collisions", 0, JColor.Yellow);
		
				font.RenderLine("Press SPACE to add an elastic sphere", 0, JColor.Yellow);
		
				font.RenderLine("Press RETURN to add a non elastic sphere", 0, JColor.Yellow);
		
				// End fonts rendering
				Jad.Video.Fonts.End();
			}
		
			// End the scene
			Jad.Scene.End();
		}
		
		/// <summary>
		/// Show the hits remaining to break the joint
		/// </summary>
		/// <param name="font">Font to render the text</param>
		void RenderHits(JFont font)
		{
			// The meshes
			for (int i = 0; i < Jad.Scene.MeshObjectsToRender.Count; i++)
			{
				JMeshObject meshObject = Jad.Scene.MeshObjectsToRender[i];
		
				int x, y;
		
				if (meshObject is MyMeshObject)
				{
					MyMeshObject hinge = (MyMeshObject)meshObject;
		
					Vector3 screen = JMath.Projection(Vector3.Empty, hinge.WorldTM);
					x = (int)screen.X;
					y = (int)screen.Y;
					if (screen.Z >= 0 && screen.Z <= 1)
						font.Render(hinge.Hits.ToString(), x, y, JColor.White);
				}
			}
		}
		
		#endregion
	}
		
	/// <summary>
	/// Example mesh object class for the tutorial
	/// </summary>
	public class MyMeshObject : JMeshObject
	{
		#region Fields
		
		/// <summary>
		/// Number of hits the object can recieve
		/// </summary>
		public float Hits;
		
		#endregion
		
		#region Constructors
		
		/// <summary>
		/// Default constructor
		/// </summary>
		/// <param name="name">Name of the object</param>
		public MyMeshObject(string name)
			: base(name, false)
		{
			Hits = 10;
		}
		
		#endregion
	}
}


JMain.cs

#region Using directives

using System;
using System.IO;

#endregion

namespace Tutorial
{
	/// <summary>
	/// Class that holds the main method. It´s the application entry point
	/// </summary>
	public class JMain
	{
		#region Methods

		/// <summary>
		/// Application entry point
		/// </summary>
		[STAThreadAttribute]
		static void Main()
		{
			// Set the engine base directory (where the configuration.xml file is located)
			JadEngine.Core.JPath.ChangeDirectory();

			// Create a new file where we´ll write console output
			StreamWriter sw = new StreamWriter("out.txt");

			// Redirect console output to this file
			Console.SetOut(sw);

			// Create the application object
			JTutorial main = new JTutorial();

			// Start the application
			main.Start();

			// Close console output file
			sw.Close();
		}

		#endregion
	}
}

JMain.cs

#region Using directives
	
using System;
using System.IO;
	
#endregion
	
namespace Tutorial
{
	/// <summary>
	/// Class that holds the main method. It´s the application entry point
	/// </summary>
	public class JMain
	{
		#region Methods
	
		/// <summary>
		/// Application entry point
		/// </summary>
		[STAThreadAttribute]
		static void Main()
		{
			// Set the engine base directory (where the configuration.xml file is located)
			JadEngine.Core.JPath.ChangeDirectory();
	
			// Create a new file where we´ll write console output
			StreamWriter sw = new StreamWriter("out.txt");
	
			// Redirect console output to this file
			Console.SetOut(sw);
	
			// Create the application object
			JTutorial main = new JTutorial();
	
			// Start the application
			main.Start();
	
			// Close console output file
			sw.Close();
		}
	
		#endregion
	}
}

Last edited Jul 24, 2006 at 4:49 PM by Vicente, version 2

Comments

No comments yet.