示例#1
0
/* The ground uses indexed drawing to draw the ground in an efficient way.  2 buffers are created, one for the vertices and one for the indices which point to a specific vertex.
 */
Ground::Ground() {
	hmScale = glm::vec3(1000.f, 200.f, 1000.f);
	std::cout << loadGroundTexture("Models/sandGrass.jpg");
	loadHeightMap("Models/test1.bmp");

	std::cout << "height at 5, 5: " << getHeight(5.f, 5.f);
}
示例#2
0
/*
================
 Terrain::init
================
*/
bool Terrain::init( ID3D10Device* device, char* heightmapFilename, WCHAR* textureFilename )
{
	bool result;
	
	result = loadHeightMap(heightmapFilename);
	if (!result)
	{
		return false;
	}

	normalizeHeightMap();

	result = calculateNormals();
	if (!result)
	{
		return true;
	}
	
	calculateTextureCoordinates();

	result = loadTexture(device, textureFilename);
	if (!result)
	{
		return false;
	}

	result = initBuffers(device);
	if (!result)
	{
		return false;
	}

	return true;
}
示例#3
0
// init data
bool Terrain::init (const char *filename) {
    // try to load map
    printf ("\nLOADING TERRAIN...\n", filename);
    printf ("\tMap file: %s\n", filename);
    if (!loadHeightMap (filename))
        return false;

    int v_index = 0;					// index for vertex array
    int n_index = 0;					// index for normal array
    float x, z;							// temp coord

    SDL_LockSurface(map_h);
    size = map_h -> w;

    num_vert = (long) (map_h -> w * map_h -> h * 4 / (res * res));
    vertex = new Vector[num_vert];			// allocate vertex memory
    texcoord = new TexCoord[num_vert];		// allocate texture memory
    num_normal = (long) (map_h -> w * map_h -> h / (res * res));
    normal = new Vector[num_normal];			// allocate normal memory
    printf ("\tVertex num: %d\n", num_vert);

    // loop for init vertex
    for (int i = 0; i < map_h -> w; i += (int) res) {			// width
        for (int j = 0; j < map_h -> h; j += (int) res) {		// height
            for (int n_tri = 0; n_tri < 4; n_tri++) {				// polygon
                // x, y
                x = (float) i + ( ( n_tri == 1 || n_tri == 2) ? res : 0.0f );
                z = (float) j + ( ( n_tri == 2 || n_tri == 3) ? res : 0.0f );

                // set vertex
                vertex[v_index].x = (x - ( map_h -> w / 2 ));
                vertex[v_index].z = (z - ( map_h -> h / 2 ));
                vertex[v_index].y = getHeightFromMap (x, z);

                // set texture coord
                texcoord[v_index].u = x / map_h -> w;
                texcoord[v_index].v = z / map_h -> h;

                v_index++;			// go to next vertex
            }
            // calculate normal coord
            Vector ab, bc;
            vectorSubtract (vertex[v_index-3], vertex[v_index-2], ab);
            vectorSubtract (vertex[v_index-2], vertex[v_index-1], bc);
            crossProduct (ab, bc, normal[n_index]);
            normalize (normal[n_index]);

            n_index++;
        }
    }
    SDL_UnlockSurface(map_h);

    return true;
}
HRESULT Heightmap::init(ID3D11Device* device,ID3D11DeviceContext* deviceContext,Shader* shader,char* heightMapPath, DWORD m, DWORD n, float dx)
{
	HRESULT hr = S_OK;
	mDevice = device;
	mDeviceContext = deviceContext;
	mShader = shader;

	hr = D3DX11CreateShaderResourceViewFromFile(device,"../Textures/ggrass.dds",0,0,&mAlbedoMap,0);

	mNumRows  = m;
	mNumCols  = n;

	mCellSpacing = dx;

	mNumVertices = mNumRows*mNumCols;
	mNumFaces    = (mNumRows-1)*(mNumCols-1)*2;

	mHeightOffset = -1.5;
	mHeightScale = 0.25;

	loadHeightMap(heightMapPath);
	smooth();

	Vertex* vertexArray = new Vertex[mNumVertices];

	float halfWidth = (mNumCols-1)*mCellSpacing*0.5f;
	float halfDepth = (mNumRows-1)*mCellSpacing*0.5f;
	
	float du = 1.0f / (mNumCols-1);
	float dv = 1.0f / (mNumRows-1);

	for(DWORD i = 0; i < mNumRows; ++i)
	{
		float z = halfDepth - i*dx;
		for(DWORD j = 0; j < mNumCols; ++j)
		{
			int vIndex = i*mNumCols+j;
			vertexArray[vIndex].pos		= D3DXVECTOR3(-halfWidth + j*dx, mHeightmap[i*mNumCols+j]-5, z);
			vertexArray[vIndex].texC	= D3DXVECTOR2(j*du, i*dv);
			vertexArray[vIndex].normal	= D3DXVECTOR3();
		}
	}

	CalculateNormals(vertexArray);
	InitBuffers(vertexArray);

	delete vertexArray;
	return hr;
}
示例#5
0
文件: a.c 项目: mlang03/School
/*  Main Loop
 *  Open window with initial window size, title bar, 
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
   srand(time(NULL));
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
   glutInitWindowSize (1024, 768);
   glutCreateWindow (argv[0]);
   init();
   loadHeightMap(argc,argv);
   calcSurfaceNormals();
   calcVertexNormals();
   calcVertexColour(0);
   glutReshapeFunc(reshape);
   glutDisplayFunc(display);
   glutKeyboardFunc (keyboard);
   glutMouseFunc (mouse);
   glutMotionFunc(up);
   glutMainLoop();
   return 0; 
}
示例#6
0
void Terrain::init()
{
	// material
	material = new Material(v4(0.2), v4(0.7), v4(0.0), 0.5);

	// load & create shaders
	int shaderID = shaderManager->loadShader("Terrain", TERRAIN_VS_FILENAME, TERRAIN_FS_FILENAME);
	shader = shaderManager->getShader(shaderID);
	border_values_location = shader->getLocation("border_values");
	border_widths_location = shader->getLocation("border_widths");
	heightInterval_location = shader->getLocation("visibleHeightInterval");

	// load heightmap
	int resolution_x = TERRAIN_RESOLUTION_X;
	int resolution_y = TERRAIN_RESOLUTION_Y;
	float size_x = TERRAIN_SIZE_X;
	float size_y = TERRAIN_SIZE_Y;
	float step_x =size_x/float(resolution_x);
	float step_y =size_y/float(resolution_y);
	red_x = 1.f/step_x;
	red_y = 1.f/step_y;

	loadHeightMap(HEIGHTMAP_SOURCE, resolution_x, resolution_y);

	// load textures
	loadTextures(TERRAIN_TEX_NAME, TERRAIN_TEX_COUNT);

	// shadow map
	shader->linkTexture(textureManager->getTexture(textureManager->shadowMapID));
	LCmatrixLoc					= shader->getLocation("LightMVPCameraVInverseMatrix");
	shadowMappingEnabledLoc		= shader->getLocation("shadowMappingEnabled");
	fastModeLoc					= shader->getLocation("fastMode");
	LMV_CVImatrixLoc			= shader->getLocation("LightMViewCameraViewInverseMatrix");
	LPmatrixLoc					= shader->getLocation("LightProjectionMatrix");

	dim_x = resolution_x;
	dim_y = resolution_y;
	drawingMethod = GL_TRIANGLE_STRIP;
	
	// create grid of triangles
	glGenBuffers(1, &eboId);
	glGenBuffers(1, &vboId);
	int ch = 3;

	
	vertices = new GLfloat[dim_x*dim_y*ch];
	normals  = new GLfloat[dim_x*dim_y*ch];
	texCoords  = new GLfloat[dim_x*dim_y*2];
	elements = new GLuint[(dim_x-1)*2*dim_y];

	channels	[INDEX]		= 1;
	channels	[VERTEX]	= 3;
	channels	[NORMAL]	= 3;
	channels	[TEXCOORD0] = 2;

	typeSizes	[INDEX]		= sizeof(GLuint);
	typeSizes	[VERTEX]	= sizeof(GLfloat);
	typeSizes	[NORMAL]	= sizeof(GLfloat);
	typeSizes	[TEXCOORD0] = sizeof(GLfloat);

	glTypes		[INDEX]		= GL_UNSIGNED_INT;
	glTypes		[VERTEX]	= GL_FLOAT;
	glTypes		[NORMAL]	= GL_FLOAT;
	glTypes		[TEXCOORD0] = GL_FLOAT;

	for (int k = 0; k < VBO_ATR_COUNT; k++){
			sizes[k]=0;
	}
	sizes		[INDEX]		= (dim_x-1)*2*dim_y * channels[INDEX]	* typeSizes[INDEX];
	sizes		[VERTEX]	= dim_x * dim_y * channels[VERTEX]	* typeSizes[VERTEX];
	sizes		[NORMAL]	= dim_x * dim_y * channels[NORMAL]	* typeSizes[NORMAL];
	sizes		[TEXCOORD0] = dim_x * dim_y * channels[TEXCOORD0]* typeSizes[TEXCOORD0];

	offsets		[INDEX]		= 0;
	offsets		[VERTEX]	= 0;
	offsets		[NORMAL]	= offsets [VERTEX] + sizes [VERTEX];
	offsets		[TEXCOORD0] = offsets [NORMAL] + sizes [NORMAL];
	
	int x,y,n;
	vboCount = 0;
	float tex_cnt_x = 100.f;
	float tex_cnt_y = 100.f;

	sz_x = size_x;
	sz_y = size_y;
	float sx2 = sz_x/2.f;
	float sy2 = sz_y/2.f;
	int hx, hy;
	for (x=0; x<dim_x; x++){
		for (y=0; y<dim_y; y++){

			vertices[(x*dim_y + y)*ch + 0] = x*step_x - sx2;//x
			vertices[(x*dim_y + y)*ch + 1] = getHeightAt(x,y);//height
			vertices[(x*dim_y + y)*ch + 2] = y*step_y - sy2;//y
			
			// normals
			v3 normal;
			
			normal.x = getHeightAt(x-1,y) - getHeightAt(x+1,y);
			normal.y = step_x;
			normal.z = getHeightAt(x,y-1) - getHeightAt(x,y+1);
			normal.normalize();

			if (normal.y<0){
				normal = -normal;
			}
			
			normals[(x*dim_y + y)*ch + 0] = normal.x;
			normals[(x*dim_y + y)*ch + 1] = normal.y;
			normals[(x*dim_y + y)*ch + 2] = normal.z;

			// texCoords
			texCoords[(x*dim_y + y)*2 + 0] = x * tex_cnt_x / dim_x;
			texCoords[(x*dim_y + y)*2 + 1] = y * tex_cnt_y / dim_y;

			vboCount += 3;
		}
	}
	int eli = 0;
	bool reverse = false;
	for (x=0; x<dim_x-1; x++){
		if (!reverse){
			for (y=0; y<dim_y; y++){
				elements[eli] = (x+1)*dim_y + y;
				eli++;
				elements[eli] = (x)*dim_y + y;
				eli++;
			}
		} else {
			for (y=dim_y-1; y>=0; y--){
				elements[eli] = (x)*dim_y + y;
				eli++;
				elements[eli] = (x+1)*dim_y + y;
				eli++;
			}
		}
		reverse = !reverse;
	}
	eboCount = eli;

	// total vbo buffer size
	int vboSize=0;
	for (int b = 0; b < VBO_ATR_COUNT; b++){
		if (b!=INDEX){
			vboSize+=sizes[b];
		}
	}

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizes[INDEX], elements, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, vboId);
		// alloc space
		glBufferData(GL_ARRAY_BUFFER, vboSize, 0, GL_STATIC_DRAW); 
		// fill vertices
		glBufferSubData(GL_ARRAY_BUFFER, offsets[VERTEX], sizes[VERTEX], vertices); 
		// fill normals
		glBufferSubData(GL_ARRAY_BUFFER, offsets[NORMAL], sizes[NORMAL], normals);
		// fill texcoords
		glBufferSubData(GL_ARRAY_BUFFER, offsets[TEXCOORD0], sizes[TEXCOORD0], texCoords);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}
示例#7
0
/// <summary>
/// Crea la malla de un terreno en base a un Heightmap
/// </summary>
/// <param name="heightmapPath">Imagen de Heightmap</param>
/// <param name="scaleXZ">Escala para los ejes X y Z</param>
/// <param name="scaleY">Escala para el eje Y</param>
/// <param name="center">Centro de la malla del terreno</param>
void TgcSimpleTerrain::loadHeightmap(string heightmapPath, float scaleXZ, float scaleY, Vector3 center)
{
	Device d3dDevice = GuiController::Instance.D3dDevice;
	this->center = center;

	//Dispose de VertexBuffer anterior, si habia
	if (!vbTerrain.Disposed())
	{
		vbTerrain.Dispose();
	}

	//cargar heightmap
	heightmapData = loadHeightMap(d3dDevice, heightmapPath);
	float width = (float)heightmapData.GetLength(0);
	float length = (float)heightmapData.GetLength(1);


	//Crear vertexBuffer
	int vertexSize = CustomVertex::PositionTextured::Size();
	totalVertices = 2 * 3 * (heightmapData.GetLength(0) - 1) * (heightmapData.GetLength(1) - 1);
	vbTerrain.Create(d3dDevice, CustomVertex::PositionTextured::Size()*totalVertices, Usage_Dynamic | Usage_WriteOnly, CustomVertex::PositionTextured::Format(), Pool_Default);

	//Cargar vertices
	int dataIdx = 0;
	vector<CustomVertex::PositionTextured> data(totalVertices);

	center.X = center.X * scaleXZ - (width / 2) * scaleXZ;
	center.Y = center.Y * scaleY;
	center.Z = center.Z * scaleXZ - (length / 2) * scaleXZ;

	for (int i = 0; i < width - 1; i++)
	{
		for (int j = 0; j < length - 1; j++)
		{
			//Vertices
			Vector3 v1 = Vector3(center.X + i * scaleXZ, center.Y + heightmapData.GetItem(i, j) * scaleY, center.Z + j * scaleXZ);
			Vector3 v2 = Vector3(center.X + i * scaleXZ, center.Y + heightmapData.GetItem(i, j + 1) * scaleY, center.Z + (j + 1) * scaleXZ);
			Vector3 v3 = Vector3(center.X + (i + 1) * scaleXZ, center.Y + heightmapData.GetItem(i + 1, j) * scaleY, center.Z + j * scaleXZ);
			Vector3 v4 = Vector3(center.X + (i + 1) * scaleXZ, center.Y + heightmapData.GetItem(i + 1, j + 1) * scaleY, center.Z + (j + 1) * scaleXZ);

			//Coordendas de textura
			Vector2 t1 = Vector2(i / width, j / length);
			Vector2 t2 = Vector2(i / width, (j + 1) / length);
			Vector2 t3 = Vector2((i + 1) / width, j / length);
			Vector2 t4 = Vector2((i + 1) / width, (j + 1) / length);

			//Cargar triangulo 1
			data[dataIdx] = CustomVertex::PositionTextured(v1, t1.X, t1.Y);
			data[dataIdx + 1] = CustomVertex::PositionTextured(v2, t2.X, t2.Y);
			data[dataIdx + 2] = CustomVertex::PositionTextured(v4, t4.X, t4.Y);

			//Cargar triangulo 2
			data[dataIdx + 3] = CustomVertex::PositionTextured(v1, t1.X, t1.Y);
			data[dataIdx + 4] = CustomVertex::PositionTextured(v4, t4.X, t4.Y);
			data[dataIdx + 5] = CustomVertex::PositionTextured(v3, t3.X, t3.Y);

			dataIdx += 6;
		}
	}


	vbTerrain.SetData(&(data[0]), totalVertices*vertexSize, LockFlags_None);
}
示例#8
0
文件: 20-map.cpp 项目: jateeq/FYDP
int main(int argc, char* argv[])
{
    //-----------------------------------------------------------------------
    // INITIALIZATION
    //-----------------------------------------------------------------------

    printf ("\n");
    printf ("-----------------------------------\n");
    printf ("CHAI 3D\n");
    printf ("Demo: 20-map\n");
    printf ("Copyright 2003-2010\n");
    printf ("-----------------------------------\n");
    printf ("\n\n");
    printf ("Instructions:\n\n");
    printf ("- Use left mouse button to rotate camera view. \n");
    printf ("- Use right mouse button to control camera zoom. \n");
    printf ("- Use haptic device and user switch to rotate \n");
    printf ("  camera or deform terrain. \n");
    printf ("\n\n");
    printf ("Keyboard Options:\n\n");
    printf ("[1] - Texture   (ON/OFF)\n");
    printf ("[2] - Wireframe (ON/OFF)\n");
    printf ("[x] - Exit application\n");
    printf ("\n\n");


    // parse first arg to try and locate resources
    resourceRoot = string(argv[0]).substr(0,string(argv[0]).find_last_of("/\\")+1);


    //-----------------------------------------------------------------------
    // 3D - SCENEGRAPH
    //-----------------------------------------------------------------------

    // create a new world.
    world = new cWorld();

    // set the background color of the environment
    // the color is defined by its (R,G,B) components.
    world->setBackgroundColor(0.1, 0.1, 0.1);

    // create a camera and insert it into the virtual world
    camera = new cCamera(world);
    world->addChild(camera);

    // define a default position of the camera (described in spherical coordinates)
    cameraAngleH = 0;
    cameraAngleV = 45;
    cameraDistance = 1.8 * MESH_SCALE_SIZE;
    updateCameraPosition();

    // set the near and far clipping planes of the camera
    // anything in front/behind these clipping planes will not be rendered
    camera->setClippingPlanes(0.01, 10.0);

    // create a light source and attach it to the camera
    light = new cLight(world);
    camera->addChild(light);                   // attach light to camera
    light->setEnabled(true);                   // enable light source
    light->setPos(cVector3d( 0.0, 0.3, 0.3));  // position the light source
    light->setDir(cVector3d(-1.0,-0.1, -0.1));  // define the direction of the light beam
    light->m_ambient.set(0.5, 0.5, 0.5);
    light->m_diffuse.set(0.8, 0.8, 0.8);
    light->m_specular.set(1.0, 1.0, 1.0);

    //-----------------------------------------------------------------------
    // 2D - WIDGETS
    //-----------------------------------------------------------------------

    // create a 2D bitmap logo
    logo = new cBitmap();

    // add logo to the front plane
    camera->m_front_2Dscene.addChild(logo);

    // load a "chai3d" bitmap image file
    bool fileload;
    fileload = logo->m_image.loadFromFile(RESOURCE_PATH("resources/images/chai3d.bmp"));
    if (!fileload)
    {
        #if defined(_MSVC)
        fileload = logo->m_image.loadFromFile("../../../bin/resources/images/chai3d.bmp");
        #endif
    }

    // position the logo at the bottom left of the screen (pixel coordinates)
    logo->setPos(10, 10, 0);

    // scale the logo along its horizontal and vertical axis
    logo->setZoomHV(0.4, 0.4);

    // here we replace all black pixels (0,0,0) of the logo bitmap
    // with transparent black pixels (0, 0, 0, 0). This allows us to make
    // the background of the logo look transparent.
    logo->m_image.replace(
                          cColorb(0, 0, 0),      // original RGB color
                          cColorb(0, 0, 0, 0)    // new RGBA color
                          );

    // enable transparency
    logo->enableTransparency(true);


    //-----------------------------------------------------------------------
    // HAPTIC DEVICES / TOOLS
    //-----------------------------------------------------------------------

    // create a haptic device handler
    handler = new cHapticDeviceHandler();

    // get access to the first available haptic device
    cGenericHapticDevice* hapticDevice;
    handler->getDevice(hapticDevice, 0);

    // retrieve information about the current haptic device
    cHapticDeviceInfo info;
    if (hapticDevice)
    {
        info = hapticDevice->getSpecifications();
    }

    // create a 3D tool and add it to the world
    tool = new cGeneric3dofPointer(world);

    // attach tool to camera
    camera->addChild(tool);

    // position tool workspace in front of camera (x-axis of camera reference pointing towards the viewer)
    tool->setPos(-cameraDistance, 0.0, 0.0);

    // connect the haptic device to the tool
    tool->setHapticDevice(hapticDevice);

    // initialize tool by connecting to haptic device
    tool->start();

    // map the physical workspace of the haptic device to a larger virtual workspace.
    tool->setWorkspaceRadius(1.0);

    // define a radius for the tool (graphical display)
    tool->setRadius(0.03);

    // hide the device sphere. only show proxy.
    tool->m_deviceSphere->setShowEnabled(false);

    // set the physical readius of the proxy.
    proxyRadius = 0.0;
    tool->m_proxyPointForceModel->setProxyRadius(proxyRadius);
	tool->m_proxyPointForceModel->m_collisionSettings.m_checkBothSidesOfTriangles = false;


    //-----------------------------------------------------------------------
    // COMPOSE THE VIRTUAL SCENE
    //-----------------------------------------------------------------------
    // create a new mesh to display a height map
    object = new cMesh(world);
    world->addChild(object);

    // load default map
    loadHeightMap();

    // read the scale factor between the physical workspace of the haptic
    // device and the virtual workspace defined for the tool
    double workspaceScaleFactor = tool->getWorkspaceScaleFactor();

    // define a maximum stiffness that can be handled by the current
    // haptic device. The value is scaled to take into account the
    // workspace scale factor
    double stiffnessMax = info.m_maxForceStiffness / workspaceScaleFactor;
    object->setStiffness(0.5 * stiffnessMax, true);

    // create a small vertical white magnetic line that will be activated when the
    // user deforms the mesh.
    magneticLine = new cShapeLine(cVector3d(0,0,0), cVector3d(0,0,0));
    world->addChild(magneticLine);
    magneticLine->m_ColorPointA.set(0.6, 0.6, 0.6);
    magneticLine->m_ColorPointB.set(0.6, 0.6, 0.6);
    magneticLine->setShowEnabled(false);

    // set haptic properties
    magneticLine->m_material.setStiffness(0.05 * stiffnessMax);
    magneticLine->m_material.setMagnetMaxForce(0.2 * info.m_maxForce);
    magneticLine->m_material.setMagnetMaxDistance(0.25);
    magneticLine->m_material.setViscosity(0.05 * info.m_maxLinearDamping);

    // create a haptic magnetic effect
    cEffectMagnet* newEffect = new cEffectMagnet(magneticLine);
    magneticLine->addEffect(newEffect);

    // disable haptic feedback for now
    magneticLine->setHapticEnabled(false);

    // create two sphere that will be added at both ends of the line
    sphereA = new cShapeSphere(0.02);
    sphereB = new cShapeSphere(0.02);
    world->addChild(sphereA);
    world->addChild(sphereB);
    sphereA->setShowEnabled(false);
    sphereB->setShowEnabled(false);

    // define some material properties for spheres
    cMaterial matSphere;
    matSphere.m_ambient.set(0.5, 0.2, 0.2);
    matSphere.m_diffuse.set(0.8, 0.4, 0.4);
    matSphere.m_specular.set(1.0, 1.0, 1.0);
    sphereA->setMaterial(matSphere);
    sphereB->setMaterial(matSphere);


    //-----------------------------------------------------------------------
    // OPEN GL - WINDOW DISPLAY
    //-----------------------------------------------------------------------

    // initialize GLUT
    glutInit(&argc, argv);

    // retrieve the resolution of the computer display and estimate the position
    // of the GLUT window so that it is located at the center of the screen
    int screenW = glutGet(GLUT_SCREEN_WIDTH);
    int screenH = glutGet(GLUT_SCREEN_HEIGHT);
    int windowPosX = (screenW - WINDOW_SIZE_W) / 2;
    int windowPosY = (screenH - WINDOW_SIZE_H) / 2;

    // initialize the OpenGL GLUT window
    glutInitWindowPosition(windowPosX, windowPosY);
    glutInitWindowSize(WINDOW_SIZE_W, WINDOW_SIZE_H);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    glutCreateWindow(argv[0]);
    glutDisplayFunc(updateGraphics);
    glutMouseFunc(mouseClick);
    glutMotionFunc(mouseMove);
    glutKeyboardFunc(keySelect);
    glutReshapeFunc(resizeWindow);
    glutSetWindowTitle("CHAI 3D");


    //-----------------------------------------------------------------------
    // START SIMULATION
    //-----------------------------------------------------------------------

    // simulation in now running
    simulationRunning = true;

    // create a thread which starts the main haptics rendering loop
    cThread* hapticsThread = new cThread();
    hapticsThread->set(updateHaptics, CHAI_THREAD_PRIORITY_HAPTICS);

    // start the main graphics rendering loop
    glutMainLoop();

    // close everything
    close();

    // exit
    return (0);
}