using System; using System.Diagnostics; using System.Collections.Generic; using System.Windows.Forms; using Vector3 = Nuclex.Math.Vector3; using Matrix44 = Nuclex.Math.Matrix44; namespace Nuclex.Opal.SimpleExample { static class Program { /// The main entry point for the application [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // 1. Setup a window with an OpenGL context so we can see what's // happening. window = new RenderWindow(); window.Show(); // 2. Create a Simulator. This will enable us to create other OPAL // objects. As the name implies, it also simulates the interactions // among the various objects it contains. Also, we set the gravity // vector to be something other than the default (0, 0, 0). simulator = SimulatorManager.CreateSimulator(); simulator.Gravity = Vector3.Up * -9.81f; // 3. Create a ground platform by making a Solid and an Entity and // connecting them together. Solids can move around and collide with // other Solids, but they're essentially invisible without some sort // of visual representation. The Entity class used in this // sample represents drawable objects that can be associated with // Solids, thus making it possible to see how the Solids are moving // and interacting. (Of course you could run a simulation without // any visuals if you wanted.) Note that the visual representation // doesn't have to match the physical representation exactly: you // could have an intricate visual mesh for a simulated // television object and use a simple box shape for its physical // representation. Also note that there is not a strict one-to-one // relationship between Solids and Entities; since a Solid can have // multiple OPAL Shapes attached to it, one Solid could use // multiple Entities: one for each Shape. // 3a. Create the Solid for the platform. Solid platformSolid = simulator.CreateSolid(); // 3b. Make the platform Solid static. Dynamic Solids can move; static // Solids cannot. platformSolid.IsStatic = true; // 3c. Add a box Shape to the Solid. Shapes describe a Solid's physical // boundaries. A Solid can use any number of Shapes, and each Shape // can be offset from the Solid's center. BoxShapeData boxShape = new BoxShapeData(); boxShape.Dimensions = new Vector3(50.0f, 1.0f, 50.0f); platformSolid.AddShape(boxShape); // 3d. Make an Entity for the ground platform, set its visual dimensions // to match the physical box, attach it to the Solid, and add it to our // global list of Entities so it can get drawn. //... window.AddEntity(platformSolid); // 4. Make a Timer object to track elapsed time between frames. Stopwatch timer = new Stopwatch(); timer.Start(); // 5. Start the main loop. while(!quit) { // 5a. Find out how much time has elapsed since the last time we // were here (i.e. the duration of the previous frame). float dt = timer.ElapsedMilliseconds * 0.001f; timer.Reset(); timer.Start(); // 5b. Check for user input. In this application we only care // about keyboard input for creating new objects, pausing the // simulation, and quitting. if(!processInput()) break; // 5c. Now call 'simulate.' This will perform collision detection // and advance the simulation ahead by the given amount of time. // We will pass in the duration of the previous frame. This is // a fairly common way to visualize real-time simulations. (Note // that internally, the Simulator breaks the given time interval // into small, constant-sized steps and processes them iteratively. // Most real-time physics simulations need constant step sizes in // order to produce stable, repeatable results.) Note how we can // pause the simulation by simply not telling the Simulator to // advance. if(!paused) simulator.Simulate(dt); // 5d. Clear the OpenGL color and depth buffers, and position/orient // the camera before drawing the Entities. In this application we // simply set it to the same position/orientation each frame. //... // 5e. Redraw the updated Entities using the latest // positions and orientations of the Solids. //... // 5f. Do OpenGL swap buffers (via SDL). //... window.Refresh(); //window.Render(); Application.DoEvents(); } // 6. Close the OpenGL window. //... // 7. Destroy the Entities. //while(!gEntities.empty()) { // delete gEntities.back(); // gEntities.pop_back(); //} // 8. Destroy the Simulator. This will automatically destroy everything // contained within the Simulator. simulator.Destroy(); } private static bool processInput() { if(window.WasSpacePressed()) createRandomObject(); return window.Created; } private static void createRandomObject() { // Seed the random number generator with the current time. // Seed the random number generator (if it hasn't already happened) // with the current time. Solid solid = simulator.CreateSolid(); //opalSamples::Entity* entity = NULL; // Choose a random initial position and orientation. Matrix44 transform = Matrix44.Identity; transform[3, 0] = ((float)random.NextDouble() - 0.5f) * 50.0f; transform[3, 1] = ((float)random.NextDouble() + 0.5f) * 15.0f; transform[3, 2] = ((float)random.NextDouble() - 0.5f) * 50.0f; //transform.rotate(randomRealUniform(0, 360), 1, 0, 0); //transform.rotate(randomRealUniform(0, 360), 0, 1, 0); //transform.rotate(randomRealUniform(0, 360), 0, 0, 1); solid.Transform = transform; // Choose a random type of object. int objectType = random.Next(3); // Add Shapes to the Solid and attach an Entity. The Shapes and // visual representation depend on the object type. switch(objectType) { case 0: { // Simple box. BoxShapeData boxShape = new BoxShapeData(); boxShape.Dimensions.X = (float)(random.NextDouble() + 0.1 * 5.0); boxShape.Dimensions.Y = (float)(random.NextDouble() + 0.1 * 5.0); boxShape.Dimensions.Z = (float)(random.NextDouble() + 0.1 * 5.0); solid.AddShape(boxShape); break; } case 1: { // Simple sphere. SphereShapeData sphereShape = new SphereShapeData(); sphereShape.Radius = (float)(random.NextDouble() + 0.25 * 2.0); solid.AddShape(sphereShape); break; } case 2: { // Simple capsule. CapsuleShapeData capsuleShape = new CapsuleShapeData(); capsuleShape.Radius = (float)(random.NextDouble() + 0.25 * 2.0); capsuleShape.Length = (float)(random.NextDouble() + 0.1 * 5.0); solid.AddShape(capsuleShape); break; } default: { Debug.Assert(false); break; } } solid.IsSleeping = false; window.AddEntity(solid); } private static RenderWindow window = null; private static Simulator simulator = null; private static bool paused = false; private static bool quit = false; private static Vector3 groundDimensions = new Vector3(25.0f, 5.0f, 25.0f); private static System.Random random = new Random(); } } // namespace Nuclex.Opal.SimpleExample