Tutorial 101: - Getting Started

From Newton Wiki
Jump to: navigation, search

Template:Languages

Download the file NewtonTutorial.zip from the Newton website and unpack it anywhere in your windows machine, if you have not done so.

These tutorials are made for Win32, compiled with visual Studio 2003 and using Simple DirectMedia Layer (SDL) for Graphics, Sound and Input. All of the elements in the tutorials are cross platform, therefore it should be simple to build then on other platform like win64, Linux, and Mac OS. However this is a basic tutorial and we will not experiment with that right now.

After unpacking go to the folder .../NewtonTutorials and open the visual studio solution NewtonTutorials.sln In the solution explorer right click on project Tutorial_101_GettingStarted and select Set as Startup Project, and click Rebuild Solution. All the dependencies are included in the download, therefore all projects should build with zero warning and zero errors.

Open up file Main.cpp, the first lines of code

#include <stdafx.h>
#include <dVector.h>
#include "OpenGlUtil.h"
#include "SceneManager.h"
#include "TutorialCode.h"
#include "CollectInputAndUpdateCamera.h"

#define USE_VISUAL_DEBUGGER

#define DEMO_PHYSICS_FPS	  120.0f
#define DEMO_FPS_IN_MICROSECUNDS  (int (1000000.0f/DEMO_PHYSICS_FPS))
#define MAX_PHYSICS_LOOPS		  1

static int g_currentTime;
static int g_physicTime;
static int g_timeAccumulator = DEMO_FPS_IN_MICROSECUNDS;

static void* g_newtonDebugger;
static NewtonWorld* g_world;
static SceneManager* g_sceneManager;

static void ShutDown ();
static void* AllocMemory (int sizeInBytes);
static void FreeMemory (void *ptr, int sizeInBytes);
static void AdvanceSimulation (int timeInMilisecunds);

#pragma warning (disable: 4100) //unreferenced formal parameter
#pragma warning (disable: 4702) //unreachable code

Are just the necessary included files, constant and variables necessary for the project to work.

The first Line in function main

_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF));

Is a operating system memory leak check handler that indicates if some memory allocation was not freed on exit. The following lines:

	// initialize graphics system
	if (!InitGraphicsSystem (800, 600)) {
		exit (0);
	}

Initializes a proper SDL Graphic System that will be used to visualize the physics scene. You are welcome to step into the function in debug mode to see how it is implemented, I will not spend time explaining the details, I will only say the code was taken almost verbatim from the SDL examples.

Next

// set a callback for destroying the world at termination
atexit (ShutDown);

A termination function is set, which will be called when the user decides to terminate the program. For most Graphics engines with a gracious ways to shutting down, this is not necessary, but graphics libraries like SDL and GLUT do not terminate with grace and all termination code has to be added during forced exit termination. The termination function looks like this:

// On termination, the application must destroy the Newton world 
void ShutDown ()
{
#ifdef USE_VISUAL_DEBUGGER
	// destroy the debugger server
	NewtonDebuggerDestroyServer (g_newtonDebugger);
#endif

	// destroy all rigid bodies, this is not necessary because Newton Destroy world will also destroy all bodies
	// but if you want to change level and restart you can call this function.
	NewtonDestroyAllBodies (g_world);

	// finally destroy the newton world 
	NewtonDestroy (g_world);

	// now we need to destroy the Graphics entities
       Delete g_sceneManager;
}

Essentially this destroys all objects created by the application in reverse order.

Next

	// Create a Simple Scene Manager
	g_sceneManager = new SceneManager();

Every Graphics engine has a way to encapsulate the various graphics components of a visual object into some kind of structure, in this tutorials will call that object Entities. In turns these Entities are encapsulated into an even higher level object called Scene Manager. A Scene Manager is an object that encapsulates most of the functionality of graphics engine. It manages the creation, destruction, user interface and motion of any graphic object. For the purposes of these tutorials the scene manager is a class that looks like this:

class SceneManager
{
	public:
	SceneManager(void);
	virtual ~SceneManager(void);

	void CreateScene ();
	Entity* CreateEntity();

	void Render ();
	SoundManager* GetSoundManager() const;
	void SetIntepolationParam(dFloat param);
	

	protected:
	int m_entCount;
	dFloat m_intepolationParam;
	SoundManager* m_soundManager;
	Entity* m_entityArray[MAX_ENTITY_COUNT];
};

Basically is a very simple flat array of Entities plus a soudn Manager object that we will use later for sounds effects.

The following lines, initializes the default settings for a Newton world

	// create the Newton World
	g_world = NewtonCreate (AllocMemory, FreeMemory);

	// use the standard x87 floating point model  
	NewtonSetPlatformArchitecture (g_world, 0);

	// set a fix world size
	dVector minSize (-500.0f, -500.0f, -500.0f);
	dVector maxSize ( 500.0f,  500.0f,  500.0f);
	NewtonSetWorldSize (g_world, &minSize[0], &maxSize[0]); 

	// initialize Newton Visual Debugger
#ifdef USE_VISUAL_DEBUGGER
	g_newtonDebugger = NewtonDebuggerCreateServer ();
#endif

	// configure the Newton world to use iterative solve mode 0
	// this is the most efficient but the less accurate mode
	NewtonSetSolverModel (g_world, 1);

The function NewtonCreate take two pointers to memory allocation functions that will take care of all the engine memory allocation. These functions are optional, you can pass NULL but you cannot pass one or the other, if you decided to control memory allocation then you must write a memory allocation and a memory free function. At the simplest level these function should look like this:

// this is the callback for allocating Newton memory
void* AllocMemory (int sizeInBytes)
{
	return malloc (sizeInBytes);
}

// this is the callback for freeing Newton Memory
void FreeMemory (void *ptr, int sizeInBytes)
{
	free (ptr);
}

The following lines show a new feature in SDK 2.00

// initialize Newton Visual Debugger
#ifdef USE_VISUAL_DEBUGGER
	g_newtonDebugger = NewtonDebuggerCreateServer ();
#endif

It is the visual debugger, at the time of the writing these tutorial the Visual Debugger Listener is not yet fully implemented.

	// now populate the world with Graphic and physical entities
	CreateScene (g_world, g_sceneManager);

In the funtion that will create the Graphical and physicals scene. The phyics scene is made out of rigid bodies, and the graphics scene is made out of Entities For these tutorials the Entity class looks like this:

class Entity
{
	public:
	struct SubMesh
	{
		unsigned m_textureHandle;
		int m_indexCount;
		unsigned short* m_indexArray;
	};

	Entity(void);
	virtual ~Entity(void);

	void OptimizeMesh();
	void LoadMesh (const char* name);
	virtual void Render (dFloat interpolationParam);

	// these are the element to represent the position and orientation state of a graphics object in the world 
	dMatrix m_matrix;					// current interpolated visual matrix
	dVector m_curPosition;				// position one physics simulation step in the future
	dVector m_prevPosition;             // position at the current physics simulation step
	dQuaternion m_curRotation;          // rotation one physics simulation step in the future  
	dQuaternion m_prevRotation;         // rotation at the current physics simulation step  


	// These are the elements for a simple vertex list index list graphics object. 
	int m_displayList;
	int m_subMeshCount;					
	int m_vertexCount;
	dFloat *m_uv;
	dFloat *m_vertex;
	dFloat *m_normal;
	SubMesh *m_subMeshes;
};

This class in not part of Newton and it is not part of any Graphics engine, It is just an easy way to group graphics functionality for these tutorial, please do not use this class as part of the physics engine. This is where the application will create and save all graphics scene objects For this simple tutorial we will create a simple scene with a big box as floor and two other smaller boxes floating on the air.

void CreateScene (NewtonWorld* world, SceneManager* sceneManager)
{
	Entity* floor;
	Entity* smilly;
	Entity* frowny;

	// Create a large body to be the floor
	floor = sceneManager->CreateEntity();
	floor->LoadMesh ("FloorBox.dat");

	// add some visual entities.
	smilly = sceneManager->CreateEntity();
	smilly->LoadMesh ("Smilly.dat");
	smilly->m_curPosition.m_y = 10.0f;
	smilly->m_prevPosition = smilly->m_curPosition;

	// add some visual entities.
	frowny = sceneManager->CreateEntity();
	frowny->LoadMesh ("Frowny.dat");
	frowny->m_curPosition.m_x = 0.5f;
	frowny->m_curPosition.m_z = 0.4f;
	frowny->m_curPosition.m_y = 10.0f;
	frowny->m_prevPosition = frowny->m_curPosition;
}

Subsequences tutorials will go straight to this function to explain the process of adding physics properties to the graphics scene.

Next we add the application main loop.

    // run the main application loop until the user terminates the demo
    for (;;) {
        // Draw the screen. 
        AdvanceSimulation (GetTimeInMicrosenconds ());
    }

This is the simplest main simulation loop we can come up with, it advances the Physical and Graphical simulation by calling AdvanceSimulation with a time elapsed since the last loop in microseconds. If you look at function AdvanceSimulation, you will find that this function has two parts. First parts updates physical simulation at a fix time step and collect the external inputs to the application. It also calls the Visual debugger to visualize the Physical Scene on the external Visual debugger.

void AdvanceSimulation (int timeInMilisecunds)
{
	// do the physics simulation here
	int deltaTime;
	int physicLoopsTimeAcc;
	dFloat fps;
	dFloat physicTime;


	// get the time step
	deltaTime = timeInMilisecunds - g_currentTime;
	g_currentTime = timeInMilisecunds;
	g_timeAccumulator += deltaTime;

	physicTime = 0;
	// advance the simulation at a fix step
	int loops = 0;
	physicLoopsTimeAcc = 0;


	while ((loops < MAX_PHYSICS_LOOPS) && (g_timeAccumulator >= DEMO_FPS_IN_MICROSECUNDS))
	{
		loops ++;

		// Process incoming events. 
		ProcessEvents (g_world);

		// sample time before the Update
		g_physicTime = GetTimeInMicrosenconds ();

		// run the newton update function
		NewtonUpdate (g_world, (1.0f / DEMO_PHYSICS_FPS));

		// calculate the time spent in the physical Simulation
		g_physicTime = GetTimeInMicrosenconds () - g_physicTime;

		// call the visual debugger to show the physics scene
#ifdef USE_VISUAL_DEBUGGER
		NewtonDebuggerServe (g_newtonDebugger, g_world);
#endif

		// subtract time from time accumulator
		g_timeAccumulator -= DEMO_FPS_IN_MICROSECUNDS;
		physicTime ++;

		physicLoopsTimeAcc += g_physicTime;
	}

	if (loops > MAX_PHYSICS_LOOPS) {
		g_physicTime = physicLoopsTimeAcc;
		g_timeAccumulator = DEMO_FPS_IN_MICROSECUNDS;
	}


	// Clear the color and depth buffers. 
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	// calculate the interpolation parameter for smooth rendering 
	g_sceneManager->SetIntepolationParam(dFloat (g_timeAccumulator) / dFloat(DEMO_FPS_IN_MICROSECUNDS));

	// do the rendering here entire Scene
	g_sceneManager->Render ();

	// display the frame rate
	// smooth the fps by averaging the last few rendering time steps;
	int dtAcc = 0;
	static int fpsIndex;
	static long int smoothFPS[128];

	smoothFPS[fpsIndex] = deltaTime;
	fpsIndex = (fpsIndex + 1) % (sizeof (smoothFPS) / sizeof (smoothFPS[0]));
	for (int i = 0; i < (sizeof (smoothFPS) / sizeof (smoothFPS[0])); i ++) {
		dtAcc += smoothFPS[i];
	}
	dtAcc /= (sizeof (smoothFPS) / sizeof (smoothFPS[0]));

	fps = 1000000.0f / dFloat (dtAcc);
	physicTime = g_physicTime * dFloat(1000.0f / 1000000.0f);
	Print (dVector (1.0f, 1.0f, 0.0f, 0.0f), 10, 10, "fps: %6.2f", fps);
	Print (dVector (1.0f, 1.0f, 0.0f, 0.0f), 10, 22, "physic time (milliseconds): %5.2f", physicTime);

	// show GL rendered Scene 
	glFlush();
	SDL_GL_SwapBuffers( );
}

Basically this is a loop designed to run the physics update at a fixed time-step. It keeps track of the delta time accumulated since the last call, every time the accumulated time is equal or larger to one physical time step, represented by const DEMO_FPS_IN_MICROSECUNDS, the loop issues a call to a NewtonUpdate, ProcessEvent, NewtonDebuggerServe and the time step is subtracted from the time accumulator.

ProcessEvent is the function in charge of collecting the user inputs for controlling the simulation. NewtonUpdate is the Newton Engine main update functions, and is does all of the physical work on all physics entities. NewtonDebuggerServe displays the physical state of the world to the external visual debugger.

The second part on this function updates the Camera, Render the Graphics Scene and display some useful information on the screen.

         
	// Clear the color and depth buffers. 
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	// calculate the interpolation parameter for smooth rendering 
	g_sceneManager->SetIntepolationParam(dFloat (g_timeAccumulator) / dFloat(DEMO_FPS_IN_MICROSECUNDS));

	// do the rendering here entire Scene
	g_sceneManager->Render ();

	// display the frame rate
	// smooth the fps by averaging the last few rendering time steps;
	int dtAcc = 0;
	static int fpsIndex;
	static long int smoothFPS[128];

	smoothFPS[fpsIndex] = deltaTime;
	fpsIndex = (fpsIndex + 1) % (sizeof (smoothFPS) / sizeof (smoothFPS[0]));
	for (int i = 0; i < (sizeof (smoothFPS) / sizeof (smoothFPS[0])); i ++) {
		dtAcc += smoothFPS[i];
	}
	dtAcc /= (sizeof (smoothFPS) / sizeof (smoothFPS[0]));

	fps = 1000000.0f / dFloat (dtAcc);
	physicTime = g_physicTime * dFloat(1000.0f / 1000000.0f);
	Print (dVector (1.0f, 1.0f, 0.0f, 0.0f), 10, 10, "fps: %6.2f", fps);
	Print (dVector (1.0f, 1.0f, 0.0f, 0.0f), 10, 22, "physic time (milliseconds): %5.2f", physicTime);

	// show GL rendered Scene 
	glFlush();
	SDL_GL_SwapBuffers( );

Here the most important part is that the rendering does not happen at the same rate than the physics, because of this, the rendering system maintains two transformation states: the old state and the state one after DEMO_FPS_IN_MICROSECUNDS has passed. The graphics system will calculate the correct transformation for visualization by interpolating the fraction of time elapsed between the two stages. The fraction of elapsed time is calculated in a variable interpolationParam

	// calculate the interpolation parameter for smooth rendering 
	g_sceneManager->SetIntepolationParam(dFloat (g_timeAccumulator) / dFloat(DEMO_FPS_IN_MICROSECUNDS));

This ends this tutorial. We have created a Graphics framework that serves as our graphics engines with a minimum set of functionality. We integrated the Newton Engine into this hypothetical graphics engine, and believe it or not it is this simple to integrate Newton in to a graphics engine. Next tutorial will demonstrate how to add Physical properties to each of the entities in of the graphics world.