BaseCommand.h


/*
-----------------------------------------------------------------------------
Filename:    BaseCommand.h
-----------------------------------------------------------------------------

This source file is generated by the Ogre AppWizard.

Check out: http://conglomerate.berlios.de/wiki/doku.php?id=ogrewizards

Based on the Example Framework for OGRE
(Object-oriented Graphics Rendering Engine)

Copyright (c) 2000-2007 The OGRE Team
For the latest info, see http://www.ogre3d.org/

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the OGRE engine.
-----------------------------------------------------------------------------
*/
#ifndef __BaseCommand_h_
#define __BaseCommand_h_


#include "ExampleApplication.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#include "../res/resource.h"
#endif

#include "BaseCommandFrameListener.h"

ET::TerrainManager							*gTerrainMgr				= NULL;
ET::SplattingManager						*gSplatMgr					= NULL;

#ifdef USE_PARTICLEUNIVERSE
ParticleUniverse::ParticleSystemManager		*gParticleSystemMgr			= NULL;
ParticleUniverse::ParticleSystem			*gExplosionParticleSystem	= NULL;
ParticleUniverse::ParticleSystem			*gFireParticleSystem		= NULL;
#endif

Caelum::CaelumSystem						*gCaelumSystem				= NULL;

// Pointers to PagedGeometry class instances:
PagedGeometry *gTrees		= NULL;
PagedGeometry *gGrass		= NULL;
PagedGeometry *gBushes		= NULL;
TreeLoader3D *gTreeLoader	= NULL;
GrassLoader *gGrassLoader	= NULL;

LogManager *gLogMgr			= NULL;

SoundManager *gSoundMgr		= NULL;

std::list< Vehicle *> gVehicles;

int			  gExplosionSoundId;
int			  gAirRaidSoundId;

/******************* NOTES *******************
- Memory leak on gGrass when calling PagedGeometry::update()
- Memory leak on gCaelumSystem
*********************************************/

// For the grass loader
inline float getTerrainHeight(const float x, const float z, void *userData = NULL)
{
	return gTerrainMgr->getTerrainInfo().getHeightAt( x, z );
}

class BaseCommandApp : public ExampleApplication
{
	Caelum::FlatCloudLayer* mCloudLayer2;

public:
	BaseCommandApp()
	{
		srand(time(NULL));
	}

	~BaseCommandApp()
	{
		if( gTrees )
		{
			delete gTrees->getPageLoader();
			SAFE_DELETE(gTrees)
		}
		if( gBushes )
		{
			delete gBushes->getPageLoader();
			SAFE_DELETE(gBushes)
		}				
		if( gGrass )
		{
			SAFE_DELETE(gGrassLoader);
			SAFE_DELETE(gGrass);
		}
		if (gCaelumSystem) 
		{
			//delete mCloudLayer2;
			SAFE_DELETE(gCaelumSystem);
            //gCaelumSystem->shutdown (true);
            //gCaelumSystem = 0;
		}	

		SAFE_DELETE(gSplatMgr);
		SAFE_DELETE(gTerrainMgr);
		SAFE_DELETE(gSoundMgr);		

		for( std::list<Vehicle*>::iterator list_iter = gVehicles.begin(); list_iter != gVehicles.end(); )
		{				
			Vehicle *p = &**list_iter;
			SAFE_DELETE(p);
			list_iter++;			
		}
	}

protected:

	virtual void createCamera(void)
	{
		// Create the camera
		mCamera = mSceneMgr->createCamera("PlayerCam");

		// position it at 500 in Z direction
		mCamera->setPosition(Vector3(0,100,80));
		// Look back along -Z
		mCamera->lookAt(Vector3(500,0,500));
		mCamera->setNearClipDistance(5);	  
		mCamera->setFarClipDistance(10000); // Default is 100000

	}

	virtual bool configure(void)
	{
		// Show the configuration dialog and initialise the system
		// You can skip this and use root.restoreConfig() to load configuration
		// settings if you were sure there are valid ones saved in ogre.cfg
		if(/*mRoot->restoreConfig() ||*/ mRoot->showConfigDialog())
		{
			// If returned true, user clicked OK so initialise
			// Here we choose to let the system create a default rendering window by passing 'true'
			mWindow = mRoot->initialise(true);
			// Let's add a nice window icon
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
			HWND hwnd;
			mWindow->getCustomAttribute("WINDOW", (void*)&hwnd);
			LONG iconID   = (LONG)LoadIcon( GetModuleHandle(0), MAKEINTRESOURCE(IDI_APPICON) );
			SetClassLong( hwnd, GCL_HICON, iconID );
#endif
			return true;
		}
		else
		{
			return false;
		}
	}


	// Just override the mandatory create scene method
	virtual void createScene(void)
	{
		// Store a copy of the log manager to our global pointer
		gLogMgr = LogManager::getSingletonPtr();
		gLogMgr->logMessage( "Initializing scene." );

		// Set ambient light
		mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

		// Set a nice skybox
		mSceneMgr->setSkyBox(true, "SkyBox");		

		// Create a light
		Light* l = mSceneMgr->createLight("MainLight");
		l->setPosition(20,80,50);
		
		initTerrain();
		initTrees();
		initGrass();
		initBushes();
		initOcean();
		initClouds();
#ifdef USE_PARTICLEUNIVERSE
		initParticles();
#endif
		initTurret();
		initSounds();

		gLogMgr->logMessage( "Done initializing scene." );
	}

	void initGrass()
	{
		//-------------------------------------- LOAD gGrass --------------------------------------
		//Create and configure a new PagedGeometry instance for grass
		gGrass = new PagedGeometry(mCamera, 100);
		gGrass->addDetailLevel<GrassPage>(500);		

		//Create a GrassLoader object
		gGrassLoader = new GrassLoader(gGrass);
		gGrass->setPageLoader(gGrassLoader);	//Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance

		//Supply a height function to gGrassLoader so it can setLeader gGrass Y values
		//HeightFunction::initialize(mSceneMgr);
		gGrassLoader->setHeightFunction(&getTerrainHeight);

		//Add some grass to the scene with gGrassLoader::addLayer()
		GrassLayer *l = gGrassLoader->addLayer("3D-Diggers/plant1sprite");

		//Configure the grass layer properties (size, density, animation properties, fade settings, etc.)
		l->setMinimumSize(2.5f, 2.5f);
		l->setMaximumSize(6.0f, 6.0f);
		l->setAnimationEnabled(true);		//Enable animations
		l->setSwayDistribution(10.0f);		//Sway fairly unsynchronized
		l->setSwayLength(0.5f);				//Sway back and forth 0.5 units in length
		l->setSwaySpeed(0.5f);				//Sway 1/2 a cycle every second
		l->setDensity(0.2f);				//Relatively dense grass
		l->setFadeTechnique(FADETECH_GROW);	//Distant gGrass should slowly raise out of the ground when coming in range
		l->setRenderTechnique(GRASSTECH_QUAD);	//Draw gGrass as scattered quads

		//This sets a color map to be used when determining the color of each grass quad. setMapBounds()
		//is used to set the area which is affected by the color map. Here, "terrain_texture.jpg" is used
		//to color the grass to match the terrain under it.
		l->setColorMap("terrain_texture.jpg");
		l->setMapBounds(TBounds(0, 0, 1500, 1500));	//(0,0)-(1500,1500) is the full boundaries of the terrain
	}

	void initClouds()
	{		
		Caelum::CaelumSystem::CaelumComponent componentMask;
		componentMask = static_cast<Caelum::CaelumSystem::CaelumComponent> (Caelum::CaelumSystem::CAELUM_COMPONENT_CLOUDS);		
		gCaelumSystem = new Caelum::CaelumSystem (Root::getSingletonPtr(), mSceneMgr, componentMask);

		//gCaelumSystem->setManageSceneFog(false);
		// Freeze cloud movement, we will update it manually
		//gCaelumSystem->setTimeScale(0); 

		// Tweak the default layer
		float farClip = mCamera->getFarClipDistance();
		// First layer by default creates a cloud at height 3000
		gCaelumSystem->getCloudSystem()->getLayer(0)->setHeight(1200.f);
		gCaelumSystem->getCloudSystem()->getLayer(0)->setFadeDistances( farClip * 0.8f, farClip );
		gCaelumSystem->getCloudSystem()->getLayer(0)->setCloudCover(0.5f);		

		// Add another layer
		/*
		Caelum::FlatCloudLayer* layer = gCaelumSystem->getCloudSystem ()->createLayerAtHeight (1800.f);								
		layer->setFadeDistances( farClip * 0.8f, farClip );
		layer->setCloudCover (0.7f);	
		layer->_ensureGeometry();
		gCaelumSystem->getCloudSystem()->addLayer(layer);				
		*/
		
		// Don't register, we will update the cloud system manually
		//mWindow->addListener (gCaelumSystem);
		//Root::getSingletonPtr()->addFrameListener (gCaelumSystem);	
	}

	void initBushes()
	{
		//Create and configure a new PagedGeometry instance for gBushes
		gBushes = new PagedGeometry(mCamera, 100);
		gBushes->addDetailLevel<BatchPage>(1500, 50);				

		//Create a new TreeLoader2D object for the gBushes
		//TreeLoader2D *bushLoader = new TreeLoader2D(gBushes, TBounds(0, 0, 1500, 1500));
		TreeLoader3D *bushLoader = new TreeLoader3D(gBushes, TBounds(0, 0, 1500, 1500));
		bushLoader->setMaximumScale(4.f);

		//Load a bush entity
		Entity *fern = mSceneMgr->createEntity("Fern", "farn1.mesh");
		Entity *plant = mSceneMgr->createEntity("Plant", "plant2.mesh");
		Entity *mushroom = mSceneMgr->createEntity("Mushroom", "shroom1_1.mesh");

		Vector3 position;
		Radian yaw;
		Real scale;
		for (int i = 0; i < 200; i++)
		{
			position.x = Math::RangeRandom(0, 1500);
			position.z = Math::RangeRandom(0, 1500);

			// Make a clear path between the turret and the base
			if( !((position.x > 700.f && position.x < 950.f) && (position.z > 1000.0f && position.z < 1250.f)))
			{
				position.y = gTerrainMgr->getTerrainInfo().getHeightAt( position.x, position.z );			 
				yaw = Degree(Math::RangeRandom(0, 360));				


				float rnd = Math::UnitRandom();
				if (rnd < 0.3f) 
				{
					scale = Math::RangeRandom(0.7f, 1.5f);
					//bushLoader->addTree(fern, position, yaw, scale);
				} 
				else if (rnd < 0.7)
				{			
					scale = Math::RangeRandom(2.0f, 4.f);
					//bushLoader->addTree(plant, position, yaw, scale);
				} 
				else 
				{
					scale = Math::RangeRandom(2.0f, 4.f);
					bushLoader->addTree(mushroom, position, yaw, scale);
				}
			}			
		}
		gBushes->setPageLoader(bushLoader);

	}

	void initTrees()
	{
		//Create and configure a new PagedGeometry instance
		gTrees = new PagedGeometry();
		gTrees->setCamera(mCamera);	//Set the camera so PagedGeometry knows how to setLeader LODs
		gTrees->setPageSize(80);	//Set the size of each page of geometry
		gTrees->setInfinite();		//Use infinite paging mode
		gTrees->addDetailLevel<BatchPage>(150, 50);		//Use batches up to # units away, and fade for # more units
		gTrees->addDetailLevel<ImpostorPage>(1500, 250);	//Use impostors up to # units, and for # more units		

		// Load a tree entity
		Entity *myEntity = mSceneMgr->createEntity("Tree", "fir05_30.mesh");
		Entity *tree2 = mSceneMgr->createEntity("Tree2", "fir14_25.mesh");


		//Create a new TreeLoader3D object
		gTreeLoader = new TreeLoader3D(gTrees, TBounds(0, 0, 1500, 1500));

		// Randomly place 20,000 copies of the tree on the terrain
		Vector3 position;
		Radian yaw;
		Real scale;
		for (int i = 0; i < 200; i++)
		{
			position.x = Math::RangeRandom(0, 1500);
			position.z = Math::RangeRandom(0, 1500);

			// Make a clear path between the turret and the base
			if( !((position.x > 500.f && position.x < 950.f) && (position.z > 500.0f && position.z < 1250.f)))
			{
				position.y = gTerrainMgr->getTerrainInfo().getHeightAt( position.x, position.z );			 
				yaw = Degree(Math::RangeRandom(0, 360));				
				scale = Math::RangeRandom(0.5f, 0.6f);
				float rnd = Math::UnitRandom();
				if (rnd < 0.5f) 
					gTreeLoader->addTree(myEntity, position, yaw, scale);
				else
					gTreeLoader->addTree(tree2, position, yaw, scale);
			}
		}	

		gTrees->setPageLoader(gTreeLoader);	//Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance			
	}

#ifdef USE_PARTICLEUNIVERSE
	void initParticles()
	{
		gParticleSystemMgr = ParticleUniverse::ParticleSystemManager::getSingletonPtr();	

		gExplosionParticleSystem = gParticleSystemMgr->createParticleSystem("mySingleSystem", "explosionSystem", mSceneMgr);			
		gExplosionParticleSystem->start();
		mSceneMgr->getRootSceneNode()->createChildSceneNode("exnode")->attachObject( gExplosionParticleSystem );

		gFireParticleSystem =  gParticleSystemMgr->createParticleSystem("fireSystem", "fireSystem", mSceneMgr);			
		gFireParticleSystem->start();	
		mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject( gFireParticleSystem );				
	}	
#endif

	void initTurret()
	{
		Entity *base = mSceneMgr->createEntity( "base", "base.mesh" );
		Entity *turret = mSceneMgr->createEntity( "turret", "turret.mesh" );
		Entity *turretgun = mSceneMgr->createEntity( "turretgun", "turretgun.mesh" );
		base->setMaterialName( "turret/base" );
		turret->setMaterialName( "turret/base" );
		turretgun->setMaterialName( "turret/base" );
		SceneNode *baseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "turret" );
		baseNode->pitch( -Radian(Math::HALF_PI) );
		baseNode->roll( Radian(Math::HALF_PI) );
		baseNode->scale( 5, 5, 5 );
		float posY = gTerrainMgr->getTerrainInfo().getHeightAt( 866.f, 1229.f );
		baseNode->setPosition( 866.f, posY + 1.f, 1229.f );				
		baseNode->attachObject( base );

		// Attach cam to turret sceneNode too
		{			
			Vector3 lookAt = baseNode->getPosition();
			lookAt.normalise();
			mCamera->detatchFromParent();
			mCamera->setPosition(0.f, 0.f, 0.f);						
			mCamera->lookAt(Vector3::UNIT_X);
			SceneNode *camnode = baseNode->createChildSceneNode( Vector3( 0.0f /* pull the cam a little back */, 0.f, 2.2f /* move the cam up a little bit */ ) );
			camnode->pitch(Radian(Math::HALF_PI)); // Re-orient the cam to take into account the pitch needed by the turret
			camnode->attachObject( mCamera );							
		}		

		SceneNode *turretNode = baseNode->createChildSceneNode( "turretnode", Vector3( 0, 0, 0.7 ) );
		turretNode->attachObject( turret );

		SceneNode *turretGunNode = turretNode->createChildSceneNode( "gunnode",  Vector3( 1.5, 0, 0 ) );
		turretGunNode->attachObject( turretgun );	
	}


	void initOcean()
	{
		// Define a plane mesh that will be used for the ocean surface
		Ogre::Plane oceanSurface;
		oceanSurface.normal = Ogre::Vector3::UNIT_Y;
		oceanSurface.d = 0;
		Ogre::MeshManager::getSingleton().createPlane("OceanSurface",
			Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
			oceanSurface, 10000, 10000, 50, 50, true, 1, 1, 1, Ogre::Vector3::UNIT_Z);

		Entity *mOceanSurfaceEnt = mSceneMgr->createEntity( "OceanSurface", "OceanSurface" );
		mOceanSurfaceEnt->setCastShadows(false);
		mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(1250.f, 67.0f, 1250.f))->attachObject(mOceanSurfaceEnt);
		mOceanSurfaceEnt->setMaterialName("OceanCg");
	}

	void initTerrain()
	{
		// create terrain manager
		gTerrainMgr = new ET::TerrainManager(mSceneMgr);
		gTerrainMgr->setLODErrorMargin(2, mCamera->getViewport()->getActualHeight());
		gTerrainMgr->setUseLODMorphing(true, 0.2, "morphFactor");

		// Load the height map
		Image image;
		image.load("level.bmp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

		ET::TerrainInfo terrainInfo; 
		ET::loadHeightmapFromImage( terrainInfo, image ); 				
		// set position and size of the terrain
		terrainInfo.setExtents(AxisAlignedBox(0, 0, 0, 1500, 500, 1500));
		// now render it
		gTerrainMgr->createTerrain(terrainInfo);		

		// Load blend map
		Image blendMap[3];
		blendMap[0].load( "ETcoverage.0.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
		blendMap[1].load( "ETcoverage.1.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
		blendMap[2].load( "ETcoverage.2.png", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );

		// create the splatting manager
		gSplatMgr = new ET::SplattingManager("ETSplatting", "ET", 256, 256, 3);
		// specify number of splatting textures we need to handle
		gSplatMgr->setNumTextures(9);
		for( int i = 0; i < 3; i++)
		{
			gSplatMgr->loadMapFromImage( i, blendMap[i] );
		}			

		// create a manual lightmap texture
		TexturePtr lightmapTex = TextureManager::getSingleton().createManual(
			"ETLightmap", "ET", TEX_TYPE_2D, 128, 128, 1, PF_BYTE_RGB);
		Image lightmap;
		ET::createTerrainLightmap(terrainInfo, lightmap, 128, 128, Vector3(1, -1, 1), ColourValue::White,
			ColourValue(0.3, 0.3, 0.3));
		lightmapTex->getBuffer(0, 0)->blitFromMemory(lightmap.getPixelBox(0, 0));

		// load the terrain material and assign it
		MaterialPtr material (MaterialManager::getSingleton().getByName("ETTerrainMaterial"));
		gTerrainMgr->setMaterial(material);  		
	}

	void initSounds()
	{
		gSoundMgr = new SoundManager;
		gSoundMgr->Initialize(); 	    

		gExplosionSoundId = gSoundMgr->CreateSound(String("51467_smcameron_missile_explosion.wav"));
		gAirRaidSoundId = gSoundMgr->CreateSound(String("57808_guitarguy1985_carterattack_fadeout.mp3"));	
	}

	// Create new frame listener
	void createFrameListener(void)
	{
		mFrameListener= new BaseCommandFrameListener(mSceneMgr, mWindow, mCamera);
		mRoot->addFrameListener(mFrameListener);
	}
};

#endif // #ifndef __BaseCommand_h_