Rough LOD code for very large terrains

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
ultramedia
Posts: 175
Joined: Wed Dec 20, 2006 12:04 pm

Rough LOD code for very large terrains

Post by ultramedia »

Hey everyone,

I've got a rough rough solution for doing a terrain mesh that uses less and less detail as it gets further away from you. No height maps yet, there are a few bugs in it still (with bounding boxes and octave interlocking). I was hoping if I put it up, some of you might find it interesting and suggest improvements or even help me with it (remember I'm brand spanking new to C++). Also, I'm going to use the last of my newbie browny points and just paste it here (I've still got it all in the one file). Sorry, but it's very late here, and I'm too stuffed to put together a download package of it at my site.

Anyways, here you go, 40 hrs of blood sweat and tears spread out over 1200 lines of code...

Code: Select all

#include <iostream>
#include <Irrlicht.h> 

#include <time.h>

using namespace irr; 
using namespace core; 
using namespace scene; 
using namespace video; 
using namespace io; 
using namespace gui; 

#pragma comment(lib, "Irrlicht.lib") 

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SETTINGS /////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// setup key engine objects
IrrlichtDevice* device = createDevice(EDT_DIRECT3D9,dimension2d<s32>(1024,768),32,false,false,false); 
IVideoDriver* driver = device->getVideoDriver(); 
ISceneManager* smgr = device->getSceneManager(); 
IGUIEnvironment* guienv = device->getGUIEnvironment(); 
ICursorControl* CursorControl;

int binaryRef[] = { 0,1,2,4,8,16,32,64,128,256,1024 }; // couldn't remember/figure out how to do binary from i *blush* ITS LATE!!!

// keyboard registry
bool keys[irr::KEY_KEY_CODES_COUNT];
	
// mouse registry
bool mouseDownL;
bool mouseDownM;
bool mouseDownR;
f32 lastWheelMovement;
position2d<f32> cursor;
position2d<f32> cursorOld;
position2d<f32> cursorDelta;

// camera registry
f32 cameraOrbit = 45;
f32 cameraAngle = 0;
f32 cameraDistance = 30;
f32 cameraOrbitOld = 0;
f32 cameraAngleOld = 0;
f32 cameraZoomMin = 5;
f32 cameraZoomMax = 500;

// player registry
f32 playerX = 0;
f32 playerY = 0;
f32 playerZ = 0;
vector3df playerPosition = vector3df(0,0,0);
f32 playerCompass = 30;
f32 playerTurnTo = 0;
f32 playerTurnSpeed = 2;
f32 playerMoveSpeed = 0.5;

// terrain node settings
static const s32 tNode_cellWidth = 1;
static const s32 tNode_cellsPerEdge = 16;
static const s32 tNode_width = tNode_cellWidth * tNode_cellsPerEdge;
static const s32 tNode_octaves = 7;

// terrain patterns
S3DVertex verticesF[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesN[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesNE[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesE[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesSE[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesS[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesSW[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesW[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
S3DVertex verticesNW[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 

// [A]xis [A]ligned [B]ounding [B]ox in [3D] space
aabbox3d<f32> boxF,boxN,boxNE,boxE,boxSE,boxS,boxSW,boxW,boxNW; 

// number of cells * 6 (each cell has two tris, each tri has 3 indices)
u16 indicesF[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];	
u16 indicesN[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesNE[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesE[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesSE[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesS[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesSW[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesW[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
u16 indicesNW[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS : MyEventReceiver //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
class MyEventReceiver : public IEventReceiver
{
public:
	virtual bool OnEvent(const SEvent& event)
	{
		if(event.EventType == irr::EET_KEY_INPUT_EVENT)
		{
			keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
			return false;
		}

		if (event.EventType == EET_MOUSE_INPUT_EVENT) 
        { 
            // left mouse button state check
			if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)	mouseDownL = true;
			if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)		mouseDownL = false;

			// middle mouse button state check
			if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)	mouseDownM = true;
			if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP)		mouseDownM = false;

			if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
			{
				cameraDistance -= event.MouseInput.Wheel * (cameraDistance / 20) * 2;
				if(cameraDistance < cameraZoomMin) cameraDistance = cameraZoomMin;
				if(cameraDistance > cameraZoomMax) cameraDistance = cameraZoomMax;
			}

			// right mouse button state check
			if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
			{
				mouseDownR = true;
				cursorOld.X = event.MouseInput.X;
				cursorOld.Y = event.MouseInput.Y;
				cursorDelta.X = 0;
				cursorDelta.Y = 0;
				cameraOrbitOld = cameraOrbit;
				cameraAngleOld = cameraAngle;
			}
			if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)		mouseDownR = false;
			
			// mouse move check
			if(event.MouseInput.Event == EMIE_MOUSE_MOVED) 
            { 
				// add condition that right mouse button be down
				if(mouseDownR == true){
	                cursor.X = event.MouseInput.X; 
		            cursor.Y = event.MouseInput.Y; 
					cursorDelta.X = cursor.X - cursorOld.X;
					cursorDelta.Y = cursor.Y - cursorOld.Y;
					if(cursorDelta.Y > 100) cursorDelta.Y = 100;
					if(cursorDelta.Y < -100) cursorDelta.Y = -100;
					cameraOrbit = (int)(cameraOrbitOld + cursorDelta.X) % 360;
					cameraAngle = (int)(cameraAngleOld + cursorDelta.Y) % 360;
					if(cameraAngle > 88) cameraAngle = 88;
					if(cameraAngle < -88) cameraAngle = -88;
				}

            }
			return false;

        } 

		return false;
	}
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS : CterrainNode /////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CterrainNode : public ISceneNode 
{

	private: 

		IVideoDriver *driver;  // A link through to the driver object
		SMaterial Material;    // A material object of type SMaterial

		vector3df originalPosition; // first placement of the terrain node (used for repositioning based on the tile intervals)
		int nodeType; // 0=full, 1=N, 2=NE, 3=E, 4=SE, 5=S, 6=SW, 7=W, 8=NW
		bool nodeDisplay;

		// internal vertices, [A]xis [A]ligned [B]ounding [B]ox in [3D] space and indices array
		S3DVertex vertices[((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1))]; 
		aabbox3d<f32> box;
		u16 indices[(tNode_cellsPerEdge * tNode_cellsPerEdge) * 6];
		s32 defaultVertexColorR, defaultVertexColorG, defaultVertexColorB;

	public: 

		/////////////////
		// constructor //
		/////////////////

		CterrainNode(ISceneNode* parent, ISceneManager* mgr, s32 id, s32 nodeType) : ISceneNode(parent, mgr, id) 
		{ 
			// put link to videoDriver into already prepared var of type IVideoDriver
			driver = SceneManager->getVideoDriver(); 
			
			// set material settings
			Material.Wireframe = true; 
			Material.Lighting = false; 
			Material.BackfaceCulling = false; 

			// set node properties
			nodeDisplay = true;
			setNodeType(nodeType);
		}
		
		/////////////////////////
		// OnRegisterSceneNode //
		/////////////////////////

		virtual void OnRegisterSceneNode() 
		{ 
			if (IsVisible) ISceneNode::OnRegisterSceneNode(); 
		}       
		
		///////////////
		// OnAnimate //
		///////////////

		virtual void OnAnimate(u32 timeMs) 
		{ 
			ISceneNode::OnAnimate(timeMs); 
		} 

		////////////
		// render //
		////////////

		virtual void render() 
		{ 
			driver->setMaterial(Material); 
			driver->setTransform(ETS_WORLD, AbsoluteTransformation); 

			driver->drawIndexedTriangleList(&vertices[0], (tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1),&indices[0],((tNode_cellsPerEdge*tNode_cellsPerEdge)*2)); 
		} 

		////////////////////
		// getBoundingBox //
		////////////////////

		virtual const aabbox3d<f32>& getBoundingBox() const 
		{ 
			return box; 
		} 
		
		//////////////////////
		// getMaterialCount //
		//////////////////////

		virtual u32 getMaterialCount() 
		{ 
			return 1; 
		} 

		/////////////////
		// getMaterial //
		/////////////////
		
		virtual SMaterial& getMaterial(s32 i) 
		{ 
			return Material; 
		}

		/////////////////////////
		// setOriginalPosition //
		/////////////////////////

		virtual void setOriginalPosition(vector3df coords)
		{
			originalPosition = coords;
		}

		/////////////////////////
		// getOriginalPosition //
		/////////////////////////

		virtual vector3df getOriginalPosition()
		{
			return originalPosition;
		}

		////////////////////
		// setNodeDisplay //
		////////////////////

		virtual void setNodeDisplay(bool status)
		{
			nodeDisplay = status;
		}

		////////////////////
		// getNodeDisplay //
		////////////////////

		virtual bool getNodeDisplay()
		{
			return nodeDisplay;
		}

		/////////////////
		// getNodeType //
		/////////////////

		virtual int getNodeType()
		{
			return nodeType;
		}

		/////////////////
		// setNodeType //
		/////////////////

		virtual void setNodeType(int nodeType)
		{
			int vCount = ((tNode_cellsPerEdge+1) * (tNode_cellsPerEdge+1));
			int iCount = (tNode_cellsPerEdge * tNode_cellsPerEdge) * 6;

			if(nodeType==0) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesF[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesF[i];
				box = boxF;
			}
			if(nodeType==1) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesN[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesN[i];
				box = boxN;
			}
			if(nodeType==2) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesNE[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesNE[i];
				box = boxNE;
			}
			if(nodeType==3) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesE[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesE[i];
				box = boxE;
			}
			if(nodeType==4) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesSE[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesSE[i];
				box = boxSE;
			}
			if(nodeType==5) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesS[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesS[i];
				box = boxS;
			}
			if(nodeType==6) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesSW[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesSW[i];
				box = boxSW;
			}
			if(nodeType==7) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesW[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesW[i];
				box = boxW;
			}
			if(nodeType==8) {
				for(int i=0; i<vCount; i++) vertices[i] = verticesNW[i];
				for(int i=0; i<iCount; i++) indices[i] = indicesNW[i];
				box = boxNW;
			}
		}
}; 


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION : sphericalXYZ //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

vector3df sphericalXYZ(f32 compassAngle, f32 elevationAngle, f32 radius){

	compassAngle = compassAngle * -1;
	elevationAngle = elevationAngle * -1;

	elevationAngle = elevationAngle + 90;

	f32 x = radius * cos(compassAngle * PI/180.0f ) * sin(elevationAngle * PI/180.0f );
	f32 z = radius * sin(compassAngle * PI/180.0f ) * sin(elevationAngle * PI/180.0f );
	f32 y = radius * cos(elevationAngle * PI/180.0f );

	vector3df result;
	result.X = x;
	result.Y = y;
	result.Z = z;
	return result;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION : int2string ////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

stringw int2string(int intToConvert){
	char temp[50];
	sprintf(temp,"%d",intToConvert);
	return temp;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
////  MAIN  /////////////////////////////////////////////////////////////////////////////////////////////////////////////
////        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main() 
{ 
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Setup ////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	///////////////////////////
	// setup system settings //
	///////////////////////////

	MyEventReceiver rv;
	device->setEventReceiver(&rv);
	for(int x=0; x<irr::KEY_KEY_CODES_COUNT; x++) keys[x] = false;

	device->setWindowCaption(L"HUGE :: Habitat Ultramedia Game Engine"); 
	IGUIStaticText* debug_panel = guienv->addStaticText(L"Debug Window",rect<s32>(5, 5, 200, 200),false,true,0,-1,false);

	////////////////////////
	// setup the "player" //
	////////////////////////

	// temporary player proxy
	ISceneNode* cPivot1 = smgr->addCubeSceneNode(0.5,0,-1,vector3df(playerPosition.X,playerPosition.Y,playerPosition.Z));
	cPivot1->setMaterialTexture(0,driver->getTexture("media/wall.bmp"));
	cPivot1->setMaterialFlag(video::EMF_LIGHTING, false);

	ISceneNode* cPivot2 = smgr->addCubeSceneNode(2,cPivot1,-1,vector3df(0,1,0));
	cPivot2->setMaterialTexture(0,driver->getTexture("media/wall.bmp"));
	cPivot2->setMaterialFlag(video::EMF_LIGHTING, false);

	ISceneNode* cPivot3 = smgr->addCubeSceneNode(1,cPivot2,-1,vector3df(0,0,2));
	cPivot3->setMaterialTexture(0,driver->getTexture("media/wall.bmp"));
	cPivot3->setMaterialFlag(video::EMF_LIGHTING, false);

	// setup the camera
	ICameraSceneNode* myCamera = smgr->addCameraSceneNode(cPivot1, sphericalXYZ(cameraOrbit,cameraAngle,cameraDistance), cPivot1->getPosition()); 

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Terrain Patterns /////////////////////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	s32 vIndex,iIndex;
	s32 defaultVertexColorR = 0;
	s32 defaultVertexColorG = 0;
	s32 defaultVertexColorB = 0;

	////////////////////
	// Pattern : FULL //
	////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesF[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxF.reset(verticesF[0].Pos); 
	for (s32 i=0; i<vIndex; i++) boxF.addInternalPoint(verticesF[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<tNode_cellsPerEdge; i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 currentVertex = (i*(tNode_cellsPerEdge+1)) + j;

			indicesF[iIndex + 0] = currentVertex;
			indicesF[iIndex + 1] = currentVertex+tNode_cellsPerEdge+1;
			indicesF[iIndex + 2] = currentVertex+tNode_cellsPerEdge+2;
			indicesF[iIndex + 3] = currentVertex;
			indicesF[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesF[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	/////////////////////
	// Pattern : NORTH //
	/////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=(tNode_cellsPerEdge/2); i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesN[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxN.reset(vector3df(0,0,0)); 
	for (s32 i=0; i<vIndex; i++) boxN.addInternalPoint(verticesN[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 currentVertex = (i*(tNode_cellsPerEdge+1)) + j;

			indicesN[iIndex + 0] = currentVertex;
			indicesN[iIndex + 1] = currentVertex+tNode_cellsPerEdge+1;
			indicesN[iIndex + 2] = currentVertex+tNode_cellsPerEdge+2;
			indicesN[iIndex + 3] = currentVertex;
			indicesN[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesN[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	//////////////////////////
	// Pattern : NORTH EAST //
	//////////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<(tNode_cellsPerEdge/2); i++){
		for (f32 j=((tNode_cellsPerEdge/2)); j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesNE[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}
	for (f32 i=(tNode_cellsPerEdge/2); i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesNE[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxNE.reset(vector3df(0,0,0));
	for (s32 i=0; i<vIndex; i++) boxNE.addInternalPoint(verticesNE[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){
		for (s32 j=0; j<(tNode_cellsPerEdge/2); j++){ 

			s32 currentVertex = (i*((tNode_cellsPerEdge/2)+1)) + j;

			s32 quarterEndRowShove = 0;
			if(i == (tNode_cellsPerEdge/2) - 1) quarterEndRowShove = tNode_cellsPerEdge/2;

			indicesNE[iIndex + 0] = currentVertex;
			indicesNE[iIndex + 1] = currentVertex+(tNode_cellsPerEdge/2)+1+quarterEndRowShove;
			indicesNE[iIndex + 2] = currentVertex+(tNode_cellsPerEdge/2)+2+quarterEndRowShove;
			indicesNE[iIndex + 3] = currentVertex;
			indicesNE[iIndex + 4] = currentVertex+(tNode_cellsPerEdge/2)+2+quarterEndRowShove;
			indicesNE[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 part2root = tNode_cellsPerEdge/2 * ((tNode_cellsPerEdge/2)+1);
			s32 currentVertex = part2root + (i*(tNode_cellsPerEdge+1)) + j;

			indicesNE[iIndex + 0] = currentVertex;
			indicesNE[iIndex + 1] = currentVertex+tNode_cellsPerEdge+1;
			indicesNE[iIndex + 2] = currentVertex+tNode_cellsPerEdge+2;
			indicesNE[iIndex + 3] = currentVertex;
			indicesNE[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesNE[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	////////////////////
	// Pattern : EAST //
	////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=(tNode_cellsPerEdge/2); j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesE[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxE.reset(vector3df(0,0,0)); 
	for (s32 i=0; i<vIndex; i++) boxE.addInternalPoint(verticesE[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<tNode_cellsPerEdge; i++){	
		for (s32 j=0; j<(tNode_cellsPerEdge/2); j++){

			s32 currentVertex = (i*((tNode_cellsPerEdge/2)+1)) + j;

			indicesE[iIndex + 0] = currentVertex;
			indicesE[iIndex + 1] = currentVertex+(tNode_cellsPerEdge/2)+1;
			indicesE[iIndex + 2] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesE[iIndex + 3] = currentVertex;
			indicesE[iIndex + 4] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesE[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	//////////////////////////
	// Pattern : SOUTH EAST //
	//////////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<((tNode_cellsPerEdge/2)+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesSE[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}
	for (f32 i=((tNode_cellsPerEdge/2)+1); i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=((tNode_cellsPerEdge/2)); j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesSE[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxSE.reset(vector3df(0,0,0));
	for (s32 i=0; i<vIndex; i++) boxSE.addInternalPoint(verticesSE[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 currentVertex = (i*(tNode_cellsPerEdge+1)) + j;

			indicesSE[iIndex + 0] = currentVertex;
			indicesSE[iIndex + 1] = currentVertex+tNode_cellsPerEdge+1;
			indicesSE[iIndex + 2] = currentVertex+tNode_cellsPerEdge+2;
			indicesSE[iIndex + 3] = currentVertex;
			indicesSE[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesSE[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){
		for (s32 j=0; j<(tNode_cellsPerEdge/2); j++){ 

			s32 part2root = ((tNode_cellsPerEdge/2) * (tNode_cellsPerEdge+1)) + (tNode_cellsPerEdge/2);
			s32 currentVertex = part2root + (i*((tNode_cellsPerEdge/2)+1)) + j;

			indicesSE[iIndex + 0] = currentVertex;
			indicesSE[iIndex + 1] = currentVertex+(tNode_cellsPerEdge/2)+1;
			indicesSE[iIndex + 2] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesSE[iIndex + 3] = currentVertex;
			indicesSE[iIndex + 4] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesSE[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	/////////////////////
	// Pattern : SOUTH //
	/////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<((tNode_cellsPerEdge/2)+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesS[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxS.reset(verticesS[0].Pos); 
	for (s32 i=0; i<vIndex; i++) boxS.addInternalPoint(verticesS[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 currentVertex = (i*(tNode_cellsPerEdge+1)) + j;

			indicesS[iIndex + 0] = currentVertex;
			indicesS[iIndex + 1] = currentVertex+1;
			indicesS[iIndex + 2] = currentVertex+tNode_cellsPerEdge+1;
			indicesS[iIndex + 3] = currentVertex+1;
			indicesS[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesS[iIndex + 5] = currentVertex+tNode_cellsPerEdge+1;

			iIndex = iIndex + 6;

		}
	}

	//////////////////////////
	// Pattern : SOUTH WEST //
	//////////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<((tNode_cellsPerEdge/2)+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesSW[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}
	for (f32 i=((tNode_cellsPerEdge/2)+1); i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=0; j<((tNode_cellsPerEdge/2)+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesSW[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxSW.reset(vector3df(0,0,0));
	for (s32 i=0; i<vIndex; i++) boxSW.addInternalPoint(verticesSW[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 currentVertex = (i*(tNode_cellsPerEdge+1)) + j;

			indicesSW[iIndex + 0] = currentVertex;
			indicesSW[iIndex + 1] = currentVertex+tNode_cellsPerEdge+1;
			indicesSW[iIndex + 2] = currentVertex+tNode_cellsPerEdge+2;
			indicesSW[iIndex + 3] = currentVertex;
			indicesSW[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesSW[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){
		for (s32 j=0; j<(tNode_cellsPerEdge/2); j++){ 

			s32 part2root = (((tNode_cellsPerEdge/2) * (tNode_cellsPerEdge+1))) + tNode_cellsPerEdge/2;
			s32 currentVertex = part2root + (i*((tNode_cellsPerEdge/2)+1)) + j;

			s32 quarterStartRowShove = 0;
			if(i == 0) quarterStartRowShove = tNode_cellsPerEdge/2;

			indicesSW[iIndex + 0] = currentVertex-quarterStartRowShove;
			indicesSW[iIndex + 1] = currentVertex+(tNode_cellsPerEdge/2)+1;
			indicesSW[iIndex + 2] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesSW[iIndex + 3] = currentVertex-quarterStartRowShove;
			indicesSW[iIndex + 4] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesSW[iIndex + 5] = currentVertex-quarterStartRowShove+1;

			iIndex = iIndex + 6;

		}
	}

	////////////////////
	// Pattern : WEST //
	////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=0; j<((tNode_cellsPerEdge/2)+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesW[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxW.reset(verticesW[0].Pos); 
	for (s32 i=0; i<vIndex; i++) boxW.addInternalPoint(verticesW[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<tNode_cellsPerEdge; i++){	
		for (s32 j=0; j<(tNode_cellsPerEdge/2); j++){

			s32 currentVertex = (i*((tNode_cellsPerEdge/2)+1)) + j;

			indicesW[iIndex + 0] = currentVertex;
			indicesW[iIndex + 1] = currentVertex+(tNode_cellsPerEdge/2)+1;
			indicesW[iIndex + 2] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesW[iIndex + 3] = currentVertex;
			indicesW[iIndex + 4] = currentVertex+(tNode_cellsPerEdge/2)+2;
			indicesW[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}
	
	//////////////////////////
	// Pattern : NORTH WEST //
	//////////////////////////

	// create vertex objects in vertex array
	vIndex = 0;
	for (f32 i=0; i<(tNode_cellsPerEdge/2); i++){
		for (f32 j=0; j<((tNode_cellsPerEdge/2)+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesNW[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}
	for (f32 i=(tNode_cellsPerEdge/2); i<(tNode_cellsPerEdge+1); i++){
		for (f32 j=0; j<(tNode_cellsPerEdge+1); j++){
			f32 vx = j*tNode_cellWidth;
			f32 vy = 0;
			f32 vz = i*tNode_cellWidth;
			verticesNW[vIndex] = S3DVertex(vx,vy,vz, 0,1,0, SColor(255,defaultVertexColorR,defaultVertexColorG,defaultVertexColorB),j,i);
			vIndex++;
		}
	}

	// setup the bounding box
	boxNW.reset(vector3df(0,0,0));
	for (s32 i=0; i<vIndex; i++) boxNW.addInternalPoint(verticesNW[i].Pos); 
	
	// setup indices
	iIndex = 0;

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){
		for (s32 j=0; j<(tNode_cellsPerEdge/2); j++){ 

			s32 currentVertex = (i*((tNode_cellsPerEdge/2)+1)) + j;

			s32 quarterEndRowShove = 0;
			// if(i == (tNode_cellsPerEdge/2) - 1) quarterEndRowShove = tNode_cellsPerEdge/2;

			indicesNW[iIndex + 0] = currentVertex;
			indicesNW[iIndex + 1] = currentVertex+(tNode_cellsPerEdge/2)+1+quarterEndRowShove;
			indicesNW[iIndex + 2] = currentVertex+(tNode_cellsPerEdge/2)+2+quarterEndRowShove;
			indicesNW[iIndex + 3] = currentVertex;
			indicesNW[iIndex + 4] = currentVertex+(tNode_cellsPerEdge/2)+2+quarterEndRowShove;
			indicesNW[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	for (s32 i=0; i<(tNode_cellsPerEdge/2); i++){	
		for (s32 j=0; j<tNode_cellsPerEdge; j++){

			s32 part2root = tNode_cellsPerEdge/2 * ((tNode_cellsPerEdge/2)+1);
			s32 currentVertex = part2root + (i*(tNode_cellsPerEdge+1)) + j;

			indicesNW[iIndex + 0] = currentVertex;
			indicesNW[iIndex + 1] = currentVertex+tNode_cellsPerEdge+1;
			indicesNW[iIndex + 2] = currentVertex+tNode_cellsPerEdge+2;
			indicesNW[iIndex + 3] = currentVertex;
			indicesNW[iIndex + 4] = currentVertex+tNode_cellsPerEdge+2;
			indicesNW[iIndex + 5] = currentVertex+1;

			iIndex = iIndex + 6;

		}
	}

	//////////////////////////
	// create terrain nodes //
	//////////////////////////

	ITextSceneNode* debugArray[(tNode_octaves*16)];

	CterrainNode* myTerrain[(tNode_octaves*16)];
	
	for(int i=0; i<(tNode_octaves*16); i++){

		// setup octave
		int octave = floor((double)i/16) + 1;
		int octaveId = i - ((octave-1)*16);
		
		// create terrain node
		myTerrain[i] = new CterrainNode(smgr->getRootSceneNode(),smgr,i,0);
		myTerrain[i]->setScale(vector3df(binaryRef[octave],binaryRef[octave],binaryRef[octave]));

		// position terrain node
		vector3df tPos;
		tPos.X = (tNode_width*binaryRef[octave]*-2) + ((octaveId%4)*(tNode_width*binaryRef[octave]));
		tPos.Y = 0; // octave * -3;
		tPos.Z = (tNode_width*binaryRef[octave]*-1) + ((int)octaveId/4)*(tNode_width*binaryRef[octave]) ;

		myTerrain[i]->setPosition(tPos);
		myTerrain[i]->setOriginalPosition(tPos);

		// stringw debugX = (stringw)tPos.X;
		// stringw debugZ = (stringw)tPos.Z;
		// stringw debugComp = debugX + (stringw)"," + debugZ;
		// debugArray[i] = smgr->addTextSceneNode(guienv->getBuiltInFont(), stringw(debugComp).c_str(), video::SColor(255,255,255,255), myTerrain[i]);
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// DEVICE : main loop ///////////////////////////////////////////////////////////////////////////////////////////////////
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	while(device->run() && device->isWindowActive()) { 
		
		/////////////////////////
		// keyboard management //
		/////////////////////////

		// system keys
		if(keys[KEY_ESCAPE]){
			device->closeDevice();
		}
		
		// player keys

		if(keys[KEY_KEY_W] || keys[KEY_KEY_S] || keys[KEY_KEY_A] || keys[KEY_KEY_D]){ 

			// playerMoveDir
			f32 playerMoveDir;
			if(keys[KEY_KEY_W]) playerMoveDir = cameraOrbit;
			if(keys[KEY_KEY_S]) playerMoveDir = cameraOrbit-180;
			if(keys[KEY_KEY_A]) playerMoveDir = cameraOrbit-90;
			if(keys[KEY_KEY_D]) playerMoveDir = cameraOrbit+90;

			// player movement vector
			vector3df playerStep = sphericalXYZ(playerMoveDir,0,playerMoveSpeed);
			playerPosition.X -= playerStep.X;
			playerPosition.Y -= playerStep.Y;
			playerPosition.Z -= playerStep.Z;

			// player rotation brain torture
			
			if(keys[KEY_KEY_W])	playerTurnTo = cameraOrbit - 90;
			if(keys[KEY_KEY_S]) playerTurnTo = cameraOrbit + 90;
			if(keys[KEY_KEY_A]) playerTurnTo = cameraOrbit -180;
			if(keys[KEY_KEY_D]) playerTurnTo = cameraOrbit;
			
			if(playerTurnTo < 0) playerTurnTo += 360;
			if(playerTurnTo >= 360) playerTurnTo -= 360;
			
			if(playerCompass < 0) playerCompass = playerCompass + 360;
			if(playerCompass >= 360) playerCompass = playerCompass - 360;

			f32 playerTurnDir = 0;
			f32 playerTurnDelta = 0;

			if(playerCompass > playerTurnTo)
			{
				if(playerCompass - playerTurnTo < 180){
					playerTurnDir = -1;
					playerTurnDelta = playerCompass - playerTurnTo;
				} else {
					playerTurnDir = 1;
					playerTurnDelta = (360 - playerCompass) + playerTurnTo;
				}
			}

			if(playerCompass < playerTurnTo)
			{
				if(playerTurnTo - playerCompass < 180){
					playerTurnDir = 1;
					playerTurnDelta = playerTurnTo - playerCompass;
				} else {
					playerTurnDir = -1;
					playerTurnDelta = (360 - playerTurnTo) + playerCompass;
				}
			}

			f32 playerTurnAmount;

			if(playerTurnDelta < playerTurnSpeed){
				playerTurnAmount = playerTurnDelta;
			} else {
				playerTurnAmount = playerTurnSpeed;
			}
			playerCompass += (playerTurnAmount * playerTurnDir);


			cPivot1->setPosition(vector3df(playerPosition.X,playerPosition.Y,playerPosition.Z));
			cPivot2->setRotation(vector3df(0,playerCompass,0));
			myCamera->setTarget(vector3df(playerPosition.X,playerPosition.Y,playerPosition.Z));
		}
		
		///////////////////////
		// camera management //
		///////////////////////

		myCamera->setPosition(sphericalXYZ(cameraOrbit,cameraAngle,cameraDistance));

		////////////////////////
		// terrain management //
		////////////////////////

		for(int i=0; i<(tNode_octaves*16); i++){

			// set octave
			int octave = floor((double)i/16) + 1;
			int octaveId = i - ((octave-1)*16);

			// get reference positions
			vector3df tNode_currentPos = myTerrain[i]->getPosition();
			vector3df tNode_originalPos = myTerrain[i]->getOriginalPosition();

			// get trigger field boundry
			f32 triggerFieldX,triggerFieldZ;
			triggerFieldX = tNode_originalPos.X - ((tNode_width*binaryRef[octave]) * 1.5);
			triggerFieldZ = tNode_originalPos.Z - ((tNode_width*binaryRef[octave]) * 1.5);

			// get distance between player and trigger field
			f32 playerTriggerDeltaX = playerPosition.X - triggerFieldX;
			f32 playerTriggerDeltaZ = playerPosition.Z - triggerFieldZ;

			// round down the player trigger delta to a forbies number (4x4, the number of cells in an octave)
			f32 playerTriggerDeltaInForbiesX, playerTriggerDeltaInForbiesZ;
			playerTriggerDeltaInForbiesX = floor((double)(playerTriggerDeltaX / ((tNode_width*binaryRef[octave])*4)));
			playerTriggerDeltaInForbiesZ = floor((double)(playerTriggerDeltaZ / ((tNode_width*binaryRef[octave])*4)));

			// calculate the new position for the terrain node after being wrapped to the other side of its octave
			f32 newX = tNode_originalPos.X + (playerTriggerDeltaInForbiesX * ((tNode_width*binaryRef[octave])*4));
			f32 newZ = tNode_originalPos.Z + (playerTriggerDeltaInForbiesZ * ((tNode_width*binaryRef[octave])*4));

			// calculate player tile delta
			f32 playerTileDeltaX, playerTileDeltaZ;
			if(playerPosition.X < newX){ playerTileDeltaX = newX - playerPosition.X; } else { playerTileDeltaX = playerPosition.X - newX - (tNode_width*binaryRef[octave]); }
			if(playerPosition.Z < newZ){ playerTileDeltaZ = newZ - playerPosition.Z; } else { playerTileDeltaZ = playerPosition.Z - newZ - (tNode_width*binaryRef[octave]); }

			// calculate player tile deltas in tile widths (for the current octave)
			f32 ptdXinTiles = playerTileDeltaX / tNode_width;
			f32 ptdZinTiles = playerTileDeltaZ / tNode_width;

			// hide octave middle tiles that overlap with the next octave down 
			if(octave > 1 && (ptdXinTiles < 0.5 && ptdZinTiles < 0.5))
			{
				myTerrain[i]->setNodeDisplay(false);
			} else {
				myTerrain[i]->setNodeDisplay(true);
			}

			// change tile patterns to fit with off center lower octave
			if(octave > 1)
			{
				bool chopped = false;

				// set tile pattern to N?
				if(ptdXinTiles < 0.5 && ptdZinTiles > 0.5 && ptdZinTiles < 1.5 && playerPosition.Z < newZ) { myTerrain[i]->setNodeType(1); chopped = true; }
				if(ptdXinTiles > 0.5 && ptdXinTiles < 1.5 && ptdZinTiles > 0.5 && ptdZinTiles < 1.5 && playerPosition.Z < newZ && playerPosition.X < newX) { myTerrain[i]->setNodeType(2); chopped = true; }
				if(ptdXinTiles > 0.5 && ptdXinTiles < 1.5 && ptdZinTiles < 0.5 && playerPosition.X < newX) { myTerrain[i]->setNodeType(3); chopped = true; }
				if(ptdXinTiles > 0.5 && ptdXinTiles < 1.5 && ptdZinTiles > 0.5 && ptdZinTiles < 1.5 && playerPosition.Z > newZ && playerPosition.X < newX) { myTerrain[i]->setNodeType(4); chopped = true; }
				if(ptdXinTiles < 0.5 && ptdZinTiles > 0.5 && ptdZinTiles < 1.5 && playerPosition.Z > newZ) { myTerrain[i]->setNodeType(5); chopped = true; }
				if(ptdXinTiles > 0.5 && ptdXinTiles < 1.5 && ptdZinTiles > 0.5 && ptdZinTiles < 1.5 && playerPosition.Z > newZ && playerPosition.X > newX) { myTerrain[i]->setNodeType(6); chopped = true; }
				if(ptdZinTiles < 0.5 && ptdXinTiles > 0.5 && ptdXinTiles < 1.5 && playerPosition.X > newX) { myTerrain[i]->setNodeType(7); chopped = true; }
				if(ptdXinTiles > 0.5 && ptdXinTiles < 1.5 && ptdZinTiles > 0.5 && ptdZinTiles < 1.5 && playerPosition.Z < newZ && playerPosition.X > newX) { myTerrain[i]->setNodeType(8); chopped = true; }


				// if no chopping was required and the tile is not full, make it full
				int checkType = myTerrain[i]->getNodeType();
				if(chopped == false && checkType != 0) myTerrain[i]->setNodeType(0);
			}

			// debug
			// stringw debugComp = (stringw)ptdXinTiles + (stringw)"," + (stringw)ptdZinTiles;
			// debugArray[i]->setText(stringw(debugComp).c_str());
			// debugArray[i]->setTextColor(SColor(255,octave*40,octave*40,octave*40));

			// if the terrain node needs to move...
			if(newX != tNode_currentPos.X || newZ != tNode_currentPos.Z)
			{
				// transform terrain node
				myTerrain[i]->setPosition(vector3df(newX,tNode_originalPos.Y,newZ));
				myTerrain[i]->setScale(vector3df(binaryRef[octave],binaryRef[octave],binaryRef[octave]));
			}
		}
		
		///////////////////
		// debug display //
		///////////////////

		stringw displayFPS    = (stringw)"FPS : " + int2string(driver->getFPS());
		stringw displayDebug  = displayFPS + "\n";
		debug_panel->setText(stringw(displayDebug).c_str());

		//////////////////
		// render scene //
		//////////////////

		driver->beginScene(true, true, SColor(0,120,120,120)); 

		for(int i=0; i<(tNode_octaves*16); i++)
		{
			if(myTerrain[i]->getNodeDisplay() == true) myTerrain[i]->render();
		}

		smgr->drawAll(); 
		guienv->drawAll();

		driver->endScene(); 
	} 
    
   device->drop(); 
   return 0; 
} 
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Can you give us a demo to see it live?
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
ultramedia
Posts: 175
Joined: Wed Dec 20, 2006 12:04 pm

Post by ultramedia »

unfortunately, I'm still learning how to use visual studio (and C++), so I haven't been able to get a standalone executable going (on another computer) yet sorry... At lunchtime I'll try to put some fraps videos on youtube.

*edit* also, wierd - the system places terrain tiles properly 9 times out of 10 in debug mode from visual studio, but in the release executable, it drops to about 6 times out of 10. Why would the same code stuff up more in release mode?
ultramedia
Posts: 175
Joined: Wed Dec 20, 2006 12:04 pm

Post by ultramedia »

okley dokely, i have a zip at my website (windows only sorry):
http://www.ultramedia.com.au/multimedia ... r_test.zip

(make sure you've installed the visual studio 2008 redistributable or it won't run)
http://www.microsoft.com/downloads/deta ... laylang=en

Right mouse click and drag to orbit
Mouse wheel to zoom in and out
w/a/s/d for movement

Notice, it's making frequent mistakes - this doesn't happen when I run it from visual studio in debug mode :( bit scary, don't know where to even start looking to find out how to fix that... Also, I reposition terrain tiles before I loop through all of them and render them, so I don't understand why it flickers sometimes too

Having said all that, I'm REALLY enjoying working with irrlicht, it's so easy to use and the documentation is fantastic too - feeling very good about giving ogre the flick and enrolling in the school of irrology :)
doqkhanh
Posts: 158
Joined: Sat Mar 01, 2008 3:14 am
Location: Tokyo, Japan
Contact:

Post by doqkhanh »

I have got a blank gray screen only... Is it a error?

Image :?:
Ion Dune
Posts: 453
Joined: Mon Nov 12, 2007 8:29 pm
Location: California, USA
Contact:

Post by Ion Dune »

Right click and hold to move camera.
Xplod
Posts: 32
Joined: Sat Mar 29, 2008 5:48 pm
Contact:

Post by Xplod »

So if I've understood well, your code make me able to apply LOD to a mesh (OctTree) ? Like terrains mesh ?

Can you make .h/.cpp files of your code? And make an example with a terrain mesh ? I don't understand very well your code and it looks a bit hard to implement.
Thanks
ultramedia
Posts: 175
Joined: Wed Dec 20, 2006 12:04 pm

Post by ultramedia »

Hey Xplod,

The code doesn't take a mesh from somewhere else and apply LOD to it, it makes it's own meshes and then slots them together in ring shaped patterns with each outside ring being larger than the one before it.

I've added heightmaps to this code since I did this thread, but can't offer anything to download yet as I'm restructuring the app into multiple files but having MASSIVE difficulties getting the array of terrain class instances to work in a seperate header and cplusplus file.

Unfortunately, I'm pretty much stalled at this point until I figure this out.
Post Reply