SkyX Bloom, shadow, speed of sun

babyken

20-03-2010 18:14:06

I am very new to ogre and not familiar with 3D programming. Stupid question may be asked.
1. I tried skyX for whole day. but i cannot figure out how to control the speed of sun.(let's say 30 minutes for day time) I found somebody use mSkySystem which is a Calcium (something like this). What's it about and how to configure? any sample I can references to it?

2. I tried the bloom compositor and copy the code from the demo. However, the effect become the following picture. Over bloom? Well Any hints about solving it? Thanks



3. Beside after i setup the updateEnvironmentLighting, the sea become very dark and some place become very bright (take a look on the coastal). Again , i have no ideas why ~~ Even i disable the bloom, still very bright in coastal. I think bcoz the light source Light1 is following the direction of Sun. I donno if it is too strong



4.And I want to do the shadow effect by skyX. Any references again ? i think it call Depth texture shadow.

Sorry for so many question. Greatly appreciate if there is any help.

Here are the code. in fact, i copy the code from demo only. Both hydrax and skyX. Since i do not know how to config it.
/*
-----------------------------------------------------------------------------
Filename: EIE360Project.cpp
-----------------------------------------------------------------------------

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.
-----------------------------------------------------------------------------
*/

#include "EIE360Project.h"
#include "SphereContactCallback.h"



#define _def_SkyBoxNum 3

// SkyX object
SkyX::SkyX *mSkyX = 0;

// Hydrax pointer
Hydrax::Hydrax *mHydrax = 0;

Ogre::String mSkyBoxes[_def_SkyBoxNum] =
{"Sky/ClubTropicana",
"Sky/EarlyMorning",
"Sky/Clouds"};

Ogre::Vector3 mSunPosition[_def_SkyBoxNum] =
{Ogre::Vector3(0,10000,0),
Ogre::Vector3(0,10000,90000),
Ogre::Vector3(0,10000,0)};

Ogre::Vector3 mSunColor[_def_SkyBoxNum] =
{Ogre::Vector3(1, 0.9, 0.6),
Ogre::Vector3(1,0.6,0.4),
Ogre::Vector3(0.45,0.45,0.45)};

int mCurrentSkyBox = 0;

// Shadow config struct
struct ShadowConfig
{
bool Enable;
int Size;

ShadowConfig(const bool& Enable_, const int& Size_)
: Enable(Enable_)
, Size(Size_)
{
}
};

//Shadow config list
ShadowConfig mShadowConfigList[] = {ShadowConfig(false, 0), ShadowConfig(true, 512), ShadowConfig(true, 2048)};
// Current shadow mode
int mShadowMode = static_cast<int>(SM_LOW);
// To disable shadows in night
bool mForceDisableShadows = false;
bool mBloomCompositor = true;

class BloomListener: public Ogre::CompositorInstance::Listener
{
public:
void notifyMaterialSetup(Ogre::uint32 pass_id, Ogre::MaterialPtr &mat)
{
}
void notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr &mat)
{
if (pass_id == 3)
{
float bloomStrength = 0.75 + Ogre::Math::Clamp<Ogre::Real>(-mSkyX->getAtmosphereManager()->getSunDirection().y, 0, 1)*0.75;
mat->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("uBloomStrength", bloomStrength);
}
}
};

class HydraxRttListener : public Hydrax::RttManager::RttListener
{
public:
void preRenderTargetUpdate(const Hydrax::RttManager::RttType& Rtt)
{
// If needed in any case...
bool underwater = mHydrax->_isCurrentFrameUnderwater();

switch (Rtt)
{
case Hydrax::RttManager::RTT_REFLECTION:
{
// No stars in the reflection map
mSkyX->setStarfieldEnabled(false);
}
break;

case Hydrax::RttManager::RTT_REFRACTION:
{
}
break;

case Hydrax::RttManager::RTT_DEPTH: case Hydrax::RttManager::RTT_DEPTH_REFLECTION:
{
// Hide SkyX components in depth maps
mSkyX->getMeshManager()->getEntity()->setVisible(false);
mSkyX->getMoonManager()->getMoonBillboard()->setVisible(false);
}
break;
}
}

void postRenderTargetUpdate(const Hydrax::RttManager::RttType& Rtt)
{
bool underwater = mHydrax->_isCurrentFrameUnderwater();

switch (Rtt)
{
case Hydrax::RttManager::RTT_REFLECTION:
{
mSkyX->setStarfieldEnabled(true);
}
break;

case Hydrax::RttManager::RTT_REFRACTION:
{
}
break;

case Hydrax::RttManager::RTT_DEPTH: case Hydrax::RttManager::RTT_DEPTH_REFLECTION:
{
mSkyX->getMeshManager()->getEntity()->setVisible(true);
mSkyX->getMoonManager()->getMoonBillboard()->setVisible(true);
}
break;
}
}
};

/** Just to locate palmiers with a pseudo-random algoritm
*/
float seed_ = 801;
float EIE360ProjectApp::rnd_(const float& min, const float& max)
{
seed_ += Ogre::Math::PI*2.8574f + seed_*(0.3424f - 0.12434f + 0.452345f);
if (seed_ > 10000000000) seed_ -= 10000000000;
return ((max-min)*Ogre::Math::Abs(Ogre::Math::Sin(Ogre::Radian(seed_))) + min);
}

void EIE360ProjectApp::createPalms(Ogre::SceneManager *mSceneMgr)
{
const int NumberOfPalms = 12;

Ogre::SceneNode* mPalmsSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

for (int k = 0; k < NumberOfPalms; k++)
{
Ogre::Vector3 RandomPos = Ogre::Vector3(rnd_(500,2500),
0,
rnd_(500,2500));

Ogre::RaySceneQuery * raySceneQuery = mSceneMgr->
createRayQuery(Ogre::Ray(RandomPos + Ogre::Vector3(0,1000000,0),
Ogre::Vector3::NEGATIVE_UNIT_Y));

Ogre::RaySceneQueryResult& qryResult = raySceneQuery->execute();
Ogre::RaySceneQueryResult::iterator i = qryResult.begin();

if (i != qryResult.end() && i->worldFragment)
{
if (i->worldFragment->singleIntersection.y>105 || i->worldFragment->singleIntersection.y<20)
{
k--;
continue;
}

RandomPos.y = i->worldFragment->singleIntersection.y;
}
else
{
k--;
continue;
}

Ogre::Entity *mPalmEnt = mSceneMgr->createEntity("Palm"+Ogre::StringConverter::toString(k), "Palm.mesh");
Ogre::SceneNode *mPalmSN = mPalmsSceneNode->createChildSceneNode();

mPalmSN->rotate(Ogre::Vector3(-1,0,rnd_(-0.3,0.3)), Ogre::Degree(90));
mPalmSN->attachObject(mPalmEnt);
Ogre::Real Scale = rnd_(50,75);
mPalmSN->scale(Scale,Scale,Scale);
mPalmSN->setPosition(RandomPos);
}
}



//-------------------------------------------------------------------------------------
EIE360ProjectApp::EIE360ProjectApp(void)
{
//Fireball initial direction
mFireBallDirection = Vector3::ZERO;

//For robot use
mDistance = 0.0f;
robotMove = true;
timer = 0.0;

//Explosion effect buffer
mExplosionCountdown = -1;
//Check is the particle effect is using
mExplosionParticle = NULL;

//OgreNewton World
mWorld = new OgreNewt::World();

//Sound Playback
FMOD_RESULT result;
result = FMOD::System_Create(&mSoundSystem); // Create the main system object.
result = mSoundSystem->init(100, FMOD_INIT_3D_RIGHTHANDED, 0);
// Initialize FMOD.
result = mSoundSystem->createSound("../../media/EIE360/Audio/windy.wav", FMOD_DEFAULT, 0, &mSound2d);

result = mSoundSystem->createSound("../../media/EIE360/Audio/bomb2.wav", FMOD_DEFAULT, 0, &mSoundBomb);

mSoundBomb->setMode(FMOD_LOOP_OFF);

mSound2d->setMode(FMOD_LOOP_NORMAL);

//User cannot press the same button two times within a short period
mKeyBuffer = 0;
}

//-------------------------------------------------------------------------------------
EIE360ProjectApp::‾EIE360ProjectApp(void)
{
//Ogre Newton World
delete mWorld;
OgreNewt::Debugger::getSingleton().deInit();

delete mNewtonListener;

//Sound system
mSound2d->release();
mSoundBomb->release();
mSoundSystem->close();
}

void EIE360ProjectApp::playAnimation(Ogre::String action)
{
bool loop = false;

Entity* mCharacterEntity = mSceneMgr->getEntity("Character");

//robot stop
if(action != "Walk")
robotMove = false;

//Disable current animation
if(mAnimationState)
mAnimationState->setEnabled(false);

//Change the animation
mAnimationState = mCharacterEntity->getAnimationState(action);


if(action == "Die")
loop = false;
else
loop = true;

//update the animation
mAnimationState->setLoop(loop);
mAnimationState->setEnabled(true);
}

//-------------------------------------------------------------------------------------
void EIE360ProjectApp::createScene(void)
{
// setup GUI system
mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow,
Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);

mGUISystem = new CEGUI::System(mGUIRenderer);

CEGUI::Logger::getSingleton().setLoggingLevel(CEGUI::Informative);


// load scheme and set up defaults
CEGUI::SchemeManager::getSingleton().loadScheme(
(CEGUI::utf8*)"TaharezLookSkin.scheme");
mGUISystem->setDefaultMouseCursor(
(CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
mGUISystem->setDefaultFont((CEGUI::utf8*)"BlueHighway-12");
CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow");
CEGUI::MouseCursor::getSingleton().show( );
// Load Game Control Layout
CEGUI::Window* sheet = CEGUI::WindowManager::getSingleton().loadWindowLayout((CEGUI::utf8*)"Game.layout");
mGUISystem->setGUISheet(sheet);

setupEventHandlers();

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

// Light
Ogre::Light *mLight0 = mSceneMgr->createLight("Light0");
mLight0->setDiffuseColour(1, 1, 1);
mLight0->setCastShadows(false);

// Shadow caster
Ogre::Light *mLight1 = mSceneMgr->createLight("Light1");
mLight1->setType(Ogre::Light::LT_DIRECTIONAL);

// Hydrax initialization code ---------------------------------------------
// ------------------------------------------------------------------------

// Create Hydrax object
mHydrax = new Hydrax::Hydrax(mSceneMgr, mCamera, mWindow->getViewport(0));

// Create our projected grid module
Hydrax::Module::ProjectedGrid *mModule
= new Hydrax::Module::ProjectedGrid(// Hydrax parent pointer
mHydrax,
// Noise module
new Hydrax::Noise::Perlin(/*Generic one*/),
// Base plane
Ogre::Plane(Ogre::Vector3(0,1,0), Ogre::Vector3(0,0,0)),
// Normal mode
Hydrax::MaterialManager::NM_VERTEX,
// Projected grid options
Hydrax::Module::ProjectedGrid::Options(/*264 /*Generic one*/));

// Set our module
mHydrax->setModule(static_cast<Hydrax::Module::Module*>(mModule));

// Load all parameters from config file
// Remarks: The config file must be in Hydrax resource group.
// All parameters can be set/updated directly by code(Like previous versions),
// but due to the high number of customizable parameters, since 0.4 version, Hydrax allows save/load config files.
mHydrax->loadCfg("HydraxDemo.hdx");

// Create water
mHydrax->create();

// Add the Hydrax Rtt listener
mHydrax->getRttManager()->addRttListener(new HydraxRttListener());

// Hydrax initialization code end -----------------------------------------
// ------------------------------------------------------------------------
mSceneMgr->setWorldGeometry("Island.cfg");
mHydrax->getMaterialManager()->addDepthTechnique(
static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("Island"))
->createTechnique());

mHydrax->setShaderMode(Hydrax::MaterialManager::SM_HLSL);

// SkyX initialization code ---------------------------------------------
// ------------------------------------------------------------------------

// Create SkyX object
mSkyX = new SkyX::SkyX(mSceneMgr, mCamera);

// No smooth fading
mSkyX->getMeshManager()->setSkydomeFadingParameters(false);

// A little change to default atmosphere settings :)
SkyX::AtmosphereManager::Options atOpt = mSkyX->getAtmosphereManager()->getOptions();
atOpt.RayleighMultiplier = 0.003075f;
atOpt.MieMultiplier = 0.00125f;
atOpt.InnerRadius = 9.92f;
atOpt.OuterRadius = 10.3311f;
mSkyX->getAtmosphereManager()->setOptions(atOpt);

// Create the sky
mSkyX->create();

// Add a basic cloud layer
mSkyX->getCloudsManager()->add(SkyX::CloudLayer::Options(/* Default options */));

//Newly Added Code
mSkyX->getSceneManager()->g
mSkyX->getUniversalClock()->setTimeScale(1);
//->getUniversalClock ()->setTimeScale (1);

// SkyX initialization code end -----------------------------------------
// ------------------------------------------------------------------------

// Bloom compositor
Ogre::CompositorManager::getSingleton().
addCompositor(mWindow->getViewport(0), "Bloom")->addListener(new BloomListener());
Ogre::CompositorManager::getSingleton().
setCompositorEnabled(mWindow->getViewport(0), "Bloom", mBloomCompositor);

//Shadow from SkyX
// Shadows
mSceneMgr->setShadowCameraSetup(Ogre::ShadowCameraSetupPtr(new Ogre::FocusedShadowCameraSetup()));
mSceneMgr->setShadowTextureCasterMaterial("ShadowCaster");
mSceneMgr->getLight("Light1")->setShadowFarDistance(1750);
setShadowMode(mSceneMgr, static_cast<ShadowMode>(mShadowMode));



// Create palmiers
createPalms(mSceneMgr);

// Create a light
//Light* l = mSceneMgr->createLight("MainLight");
//l->setPosition(20,80,50);


//Create robot
Entity *mCharacterEntity;
SceneNode* mCharacterNode;

mCharacterEntity = mSceneMgr->createEntity("Character", "robot.mesh");
mCharacterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("CharacterNode");
mCharacterNode->attachObject(mCharacterEntity);
mCharacterNode->setPosition(Vector3(1450, 195, 1300));
mCharacterNode->yaw(Degree(270));

//Create robot animation
//AnimationState* mAnimationState;
mAnimationState = mCharacterEntity->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);


// Set skydome
mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

// Create an overlay layer (for drawing text) with a textarea
Overlay *myOverlay = OverlayManager::getSingleton().getByName("MyOverlay/Textarea");
myOverlay->show();
mTextarea = OverlayManager::getSingleton().getOverlayElement("MyOverlay/Text");

//// Create a light
//Light *light = mSceneMgr->createLight("MainLight2");
//light->setType(Light::LT_DIRECTIONAL);
//light->setPosition(1500, 400, 2000);
//light->setDirection(Vector3( 1600, -5, 1 ));


// Set camera
mCamera->setPosition(Vector3(1500, 300, 1600));
mCamera->lookAt(Vector3(1280, 0, 0));

//Particle Effect
ParticleSystem *fireballParticle = mSceneMgr->createParticleSystem("FireBall", "EIE360/FireBall");
SceneNode *mFireBallNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("FireBallNode");

mFireBallNode->attachObject(fireballParticle);
mFireBallNode->setScale(5, 5, 5);
mFireBallNode->setVisible(true);

// Ground
Entity* island = mSceneMgr->createEntity("IslandMesh", "Island.mesh" );
SceneNode *groundNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "IslandNode" );
groundNode->attachObject( island );
groundNode->setScale(50, 100, 50);
groundNode->setVisible(false);
island->setCastShadows(false);

//for cating shadow, no longer useful after hydrax
//mSceneMgr->setShadowTechnique(Ogre::ShadowTechnique::SHADOWTYPE_STENCIL_MODULATIVE);
//barrelEnt->setCastShadows(true);

// Rigid body of ground
OgreNewt::Collision* col = new OgreNewt::CollisionPrimitives::TreeCollision( mWorld, groundNode, false );
OgreNewt::Body *ground_body = new OgreNewt::Body( mWorld, col );
ground_body->attachToNode( groundNode );
ground_body->setPositionOrientation( Ogre::Vector3(1600, 0, 1600), Ogre::Quaternion(sqrt(0.5), 0, -sqrt(0.5), 0) );
delete col;

// Wooden Barrel
mBarrelNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
Entity* barrelEnt = mSceneMgr->createEntity("Barrel", "WoodenBarrel.mesh");

mBarrelNode->attachObject(barrelEnt);
mBarrelNode->setScale( Vector3(0.7) );
mBarrelNode->setPosition( 1550, 195, 1600);

//Extra 2 Wooden Barrel
SceneNode* mBarrel2Node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
Entity* barrel2Ent = mSceneMgr->createEntity("Barrel2", "WoodenBarrel.mesh");
mBarrel2Node->attachObject(barrel2Ent);
mBarrel2Node->setScale( Vector3(0.7) );
mBarrel2Node->setPosition( 1550, 195, 1600);

SceneNode* mBarrel3Node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
Entity* barrel3Ent = mSceneMgr->createEntity("Barrel3", "WoodenBarrel.mesh");
mBarrel3Node->attachObject(barrel3Ent);
mBarrel3Node->setScale( Vector3(0.7) );
mBarrel3Node->setPosition( 1550, 195, 1600);

//set newton world size
mWorld->setWorldSize(Vector3(-100, -100, -100), Vector3(3300, 500, 3300));

//Rigid body of barrel
OgreNewt::ConvexCollision *col_convex = new OgreNewt::CollisionPrimitives::ConvexHull(mWorld, mBarrelNode);
OgreNewt::Body *barrel_body = new OgreNewt::Body( mWorld, col_convex );
barrel_body->attachToNode( mBarrelNode );
barrel_body->setPositionOrientation( Ogre::Vector3(1550, 215, 1500), Ogre::Quaternion::IDENTITY);

//set the force and mass of the Barrel
Ogre::Real mass = 100;
Ogre::Vector3 inertia, offset;
col_convex->calculateInertialMatrix(inertia, offset);

barrel_body->setMassMatrix( mass, inertia );
barrel_body->setCenterOfMass(offset);
barrel_body->setStandardForceCallback();
delete col_convex;

//Extra 2 barrel in newton
col_convex = new OgreNewt::CollisionPrimitives::ConvexHull(mWorld, mBarrel2Node);
OgreNewt::Body *barrel2_body = new OgreNewt::Body( mWorld, col_convex );
barrel2_body->attachToNode( mBarrel2Node );
barrel2_body->setPositionOrientation( Ogre::Vector3(1475, 215, 1500), Ogre::Quaternion::IDENTITY);

//set the force and mass of the Barrel
col_convex->calculateInertialMatrix(inertia, offset);

barrel2_body->setMassMatrix( mass, inertia );
barrel2_body->setCenterOfMass(offset);
barrel2_body->setStandardForceCallback();
delete col_convex;

col_convex = new OgreNewt::CollisionPrimitives::ConvexHull(mWorld, mBarrel3Node);
OgreNewt::Body *barrel3_body = new OgreNewt::Body( mWorld, col_convex );
barrel3_body->attachToNode( mBarrel3Node );
barrel3_body->setPositionOrientation( Ogre::Vector3(1400, 215, 1500), Ogre::Quaternion::IDENTITY);

//set the force and mass of the Barrel
col_convex->calculateInertialMatrix(inertia, offset);

barrel3_body->setMassMatrix( mass, inertia );
barrel3_body->setCenterOfMass(offset);
barrel3_body->setStandardForceCallback();
delete col_convex;


//set the force and mass for the fireball
// Rigid body of fire ball with a radius of 15
Ogre::Vector3 size = Ogre::Vector3( 15, 15, 15);
col = new OgreNewt::CollisionPrimitives::Ellipsoid(mWorld, size);
mFireBall_body = new OgreNewt::Body( mWorld, col );
mFireBall_body->attachToNode( mFireBallNode );
delete col;

mass = 1.0;
inertia = OgreNewt::MomentOfInertia::CalcSphereSolid(mass, 10);
mFireBall_body->setMassMatrix( mass, inertia );

mFireBall_body->setStandardForceCallback();

//set the Character box
// Character box
size = Ogre::Vector3( 160, 350, 80 );
mCharacterBoxNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
Entity *boxEnt = mSceneMgr->createEntity("CharacterBox", "box.mesh");
mCharacterBoxNode->attachObject( boxEnt );
mCharacterBoxNode->setScale( size );


// Rigid body of box for character
col = new OgreNewt::CollisionPrimitives::Box( mWorld, size );
mCharacterBox_body = new OgreNewt::Body( mWorld, col );
mCharacterBox_body->attachToNode( mCharacterBoxNode );
mCharacterBoxNode->setVisible(false);
//mCharacterBox_body->attachToNode( mCharacterNode );
//mCharacterBox_body->setPositionOrientation( mCharacterNode->getPosition() + Vector3(0, 100, 0), mCharacterNode->getOrientation() );
mCharacterBox_body->setPositionOrientation( mCharacterNode->getPosition(), mCharacterNode->getOrientation() );
mCharacterBox_body->setAutoFreeze(false);
delete col;

mass = 10.0;
inertia = OgreNewt::MomentOfInertia::CalcBoxSolid( mass, size );
mCharacterBox_body->setMassMatrix( mass, inertia );

//create material ID
OgreNewt::MaterialID* character_material_id = new OgreNewt::MaterialID(mWorld);
OgreNewt::MaterialID* fireBall_material_id = new OgreNewt::MaterialID(mWorld);

OgreNewt::MaterialID* barrel_id = new OgreNewt::MaterialID(mWorld);
OgreNewt::MaterialID* barrel2_id = new OgreNewt::MaterialID(mWorld);
OgreNewt::MaterialID* barrel3_id = new OgreNewt::MaterialID(mWorld);


OgreNewt::MaterialPair* pair = new OgreNewt::MaterialPair(mWorld, fireBall_material_id, character_material_id );

//create Material ID for barrels

mFireBall_body->setMaterialGroupID(fireBall_material_id);
mCharacterBox_body->setMaterialGroupID(character_material_id);

OgreNewt::MaterialPair* pair1 = new OgreNewt::MaterialPair(mWorld, fireBall_material_id, barrel_id );
OgreNewt::MaterialPair* pair2 = new OgreNewt::MaterialPair(mWorld, fireBall_material_id, barrel2_id );
OgreNewt::MaterialPair* pair3 = new OgreNewt::MaterialPair(mWorld, fireBall_material_id, barrel3_id );


OgreNewt::MaterialPair* pair4 = new OgreNewt::MaterialPair(mWorld, character_material_id, barrel_id );
OgreNewt::MaterialPair* pair5 = new OgreNewt::MaterialPair(mWorld, character_material_id, barrel2_id );
OgreNewt::MaterialPair* pair6 = new OgreNewt::MaterialPair(mWorld, character_material_id, barrel3_id );

barrel_body->setMaterialGroupID(barrel_id);
barrel2_body->setMaterialGroupID(barrel2_id);
barrel3_body->setMaterialGroupID(barrel3_id);



//event handler
SphereContactCallback* sphereCallback = new SphereContactCallback(this);
pair->setContactCallback(sphereCallback);
pair1->setContactCallback(sphereCallback);
pair2->setContactCallback(sphereCallback);
pair3->setContactCallback(sphereCallback);
pair4->setContactCallback(sphereCallback);
pair5->setContactCallback(sphereCallback);
pair6->setContactCallback(sphereCallback);

//explosion particle system
mExplosionNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("ExplosionNode");
}

/** Set shadow mode
*/
void EIE360ProjectApp::setShadowMode(Ogre::SceneManager *sm, const ShadowMode& smode)
{
Ogre::MaterialPtr IslandMat = static_cast<Ogre::MaterialPtr>(Ogre::MaterialManager::getSingleton().getByName("Island"));

if (mShadowConfigList[smode].Enable && !mForceDisableShadows)
{
sm->setShadowTechnique(Ogre::SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED);
sm->setShadowTextureConfig(0, mShadowConfigList[smode].Size, mShadowConfigList[smode].Size, Ogre::PF_X8R8G8B8);
IslandMat->getTechnique(0)->setSchemeName("Default");
IslandMat->getTechnique(1)->setSchemeName("NoDefault");
}
else
{
sm->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
IslandMat->getTechnique(0)->setSchemeName("NoDefault");
IslandMat->getTechnique(1)->setSchemeName("Default");
}
}

void EIE360ProjectApp::updateEnvironmentLighting()
{
Ogre::Vector3 lightDir = mSkyX->getAtmosphereManager()->getSunDirection();

bool preForceDisableShadows = mForceDisableShadows;
mForceDisableShadows = (lightDir.y > 0.15f) ? true : false;

if (preForceDisableShadows != mForceDisableShadows)
{
setShadowMode(mSceneMgr, static_cast<ShadowMode>(mShadowMode));
}

// Calculate current color gradients point
float point = (-lightDir.y + 1.0f) / 2.0f;
mHydrax->setWaterColor(mWaterGradient.getColor(point));

Ogre::Vector3 sunPos = mCamera->getDerivedPosition() - lightDir*mSkyX->getMeshManager()->getSkydomeRadius()*0.1;
mHydrax->setSunPosition(sunPos);

Ogre::Light *Light0 = mSceneMgr->getLight("Light0"),
*Light1 = mSceneMgr->getLight("Light1");

Light0->setPosition(mCamera->getDerivedPosition() - lightDir*mSkyX->getMeshManager()->getSkydomeRadius()*0.02);
Light1->setDirection(lightDir);

Ogre::Vector3 sunCol = mSunGradient.getColor(point);
Light0->setSpecularColour(sunCol.x, sunCol.y, sunCol.z);
Ogre::Vector3 ambientCol = mAmbientGradient.getColor(point);
Light0->setDiffuseColour(ambientCol.x, ambientCol.y, ambientCol.z);
mHydrax->setSunColor(sunCol);
}

/** Update shadow far distance
*/
void EIE360ProjectApp::updateShadowFarDistance()
{
Ogre::Light* Light1 = mSceneMgr->getLight("Light1");
float currentLength = (Ogre::Vector3(1500, 100, 1500) - mCamera->getDerivedPosition()).length();

if (currentLength < 1000)
{
mLastPositionLength = currentLength;
return;
}

if (currentLength - mLastPositionLength > 100)
{
mLastPositionLength += 100;

Light1->setShadowFarDistance(Light1->getShadowFarDistance() + 100);
}
else if (currentLength - mLastPositionLength < -100)
{
mLastPositionLength -= 100;

Light1->setShadowFarDistance(Light1->getShadowFarDistance() - 100);
}
}


void EIE360ProjectApp::startExplosion(void)
{
SceneNode* mFireBallNode = mSceneMgr->getSceneNode("FireBallNode");
if (mExplosionParticle == NULL)
{
mExplosionParticle = mSceneMgr->createParticleSystem("Explosion", "EIE360/Explosion");
mExplosionNode->attachObject(mExplosionParticle);
Node* mCharacterNode = mSceneMgr->getRootSceneNode()->getChild("CharacterNode");
//mExplosionNode->setPosition(mCharacterBoxNode->getPosition());
mExplosionNode->setPosition(mFireBallNode->getPosition());
mExplosionCountdown = 5;
}
FMOD_RESULT result;

result = mSoundSystem->playSound(FMOD_CHANNEL_FREE, mSoundBomb, false, &mChannel);
mChannel->setVolume(0.25); // Set the volume to 25% of the maximum



mFireBallNode->setVisible(false);
mFireBall_body->setPositionOrientation(Vector3(1450, 250, 1700), Quaternion::IDENTITY);
mFireBall_body->setVelocity(Vector3(0,0,0));
}


void EIE360ProjectApp::createFrameListener(void)
{
BaseApplication::createFrameListener();
mNewtonListener = new OgreNewt::BasicFrameListener( mWindow, mSceneMgr, mWorld);
mRoot->addFrameListener(mNewtonListener);
}


void EIE360ProjectApp::chooseSceneManager(void)
{
mSceneMgr = mRoot->createSceneManager("TerrainSceneManager");
}

void EIE360ProjectApp::setupEventHandlers(void)
{
CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
wmgr.getWindow((CEGUI::utf8*)"GameDemo/StartButton")->subscribeEvent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&EIE360ProjectApp::startGame, this));

CEGUI::WindowManager& wmgr2 = CEGUI::WindowManager::getSingleton();
wmgr2.getWindow((CEGUI::utf8*)"GameDemo/StopButton")->subscribeEvent( CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&EIE360ProjectApp::finishGame, this));

}


bool EIE360ProjectApp::startGame(const CEGUI::EventArgs& e)
{
std::wostringstream os;
os << L"Game Started" << std::endl;
mTextarea->setPosition(5,5);

mTextarea->setCaption(os.str());

mFireBall_body->freeze();
SceneNode* mFireBallNode = mSceneMgr->getSceneNode("FireBallNode");
mFireBallNode->setVisible(true);

Vector3 camPos = mCamera->getPosition();
mFireBall_body->setPositionOrientation(camPos, Quaternion::IDENTITY);
Node* mCharacterNode = mSceneMgr->getRootSceneNode()->getChild("CharacterNode");


//Vector3 fireballDirection = mCharacterNode->getPosition() * Vector3(1, 0, 0);
int mFireballSpeed = 1200;

Vector3 direction = mCharacterNode->getPosition() - camPos;
direction.normalise();
mFireBall_body->setVelocity(direction*mFireballSpeed);
mFireBall_body->setOmega(Vector3::ZERO);
mFireBall_body->unFreeze();





//SceneNode* mFireBallNode = mSceneMgr->getSceneNode("FireBallNode");
//Node* mCharacterNode = mSceneMgr->getRootSceneNode()->getChild("CharacterNode");
//
////so the starting position of the firball is the same as robot

//mFireBallNode->setPosition(Vector3(1450, 195, 1500));

////mFireBallDirection = mDirection * Vector3(1, 0, 1);
//mFireBallDirection = mCharacterNode->getPosition() - mFireBallNode->getPosition();
//mFireBallDirection = mFireBallDirection * Vector3(1,0,1);

//mFireBallDistance = mFireBallDirection.normalise();
//
////the fireball will move on the ground
//mFireBallNode->setVisible(true);

return true;
}

bool EIE360ProjectApp::finishGame(const CEGUI::EventArgs& e)
{
std::wostringstream os;
os << L"Game ended" << std::endl;
mTextarea->setPosition(0.5,0.5);
mTextarea->setCaption(os.str());

//reset the robot moving status
robotMove= true;
//reset the timer
timer = 0.0;

Entity* mCharacterEntity = mSceneMgr->getEntity("Character");
if(mAnimationState)
mAnimationState->setEnabled(false);
mAnimationState = mCharacterEntity->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);

return true;
}




bool EIE360ProjectApp::frameStarted(const FrameEvent& evt)
{
processCalculation(evt);

// Update the rendering
mWindow->update();

// Slow down refresh rate
Sleep(1);

return BaseApplication::frameStarted(evt);
}

void EIE360ProjectApp::updateRobotDest()
{


Node* mCharacterNode = mSceneMgr->getRootSceneNode()->getChild("CharacterNode");
//A new destination for robot
mDestination = Vector3(Math::RangeRandom(-200, 200), 0, Math::RangeRandom(-200, 200)) + Vector3(1450, 195, 1300); //original position;


//go direction
mDirection = mDestination - mCharacterNode->getPosition();


//get where the node face
Quaternion faceQuat = mCharacterNode->getOrientation();
//I donno this one
Vector3 faceVec = faceQuat * Vector3::UNIT_X;

//not sure this one either, just know set the face
//for turning the node
Quaternion quat = faceVec.getRotationTo(mDirection * Vector3(1,0,1));

//Set distance normalised
mDistance = mDirection.normalise();

/*this code are like this
mDistance = mDirection;
mDirection.normalise();*/


//turnthe node
if((1.0f + faceVec.dotProduct(mDirection)) < 0.0001f)
mCharacterNode->yaw(Degree(180));
else
mCharacterNode->rotate(quat);


return;
}

void EIE360ProjectApp::processCalculation(const FrameEvent& evt)
{
// Update Hydrax
mHydrax->update(evt.timeSinceLastFrame);

// Update SkyX
mSkyX->update(evt.timeSinceLastFrame);

updateEnvironmentLighting();
updateShadowFarDistance();

Node* mCharacterNode = mSceneMgr->getRootSceneNode()->getChild("CharacterNode");
mAnimationState->addTime(evt.timeSinceLastFrame);

//Used to allow robot walk few steps before checking is it in middle of terrain.
timer += evt.timeSinceLastFrame;

mCharacterBox_body->setPositionOrientation( mCharacterNode->getPosition(), mCharacterNode->getOrientation() );
//mDestination, a Vector3 that at the destination
//Do it when it is finish walking && it is in walking mode.
if(mDistance <= 0.0f && robotMove)
{
updateRobotDest();
}

//Check is the robot in the middle of terrain and tolerance
/*if((mCharacterNode->getPosition().x >1445 && mCharacterNode->getPosition().x <1455) && timer>5.0)
{
robotMove = false;
Entity* mCharacterEntity = mSceneMgr->getEntity("Character");

if(mAnimationState)
mAnimationState->setEnabled(false);
mAnimationState = mCharacterEntity->getAnimationState("Idle");

mAnimationState->setEnabled(true);
mAnimationState->setLoop(true);
}
else*/ if(mAnimationState->getAnimationName() != "Die") //General Case
{


//compute the norm from the vector mDirection
//At the same time, mDirection is converted to a unit vector

mWalkSpeed = 70.0f;

Real move = mWalkSpeed * evt.timeSinceLastFrame;
//The actual amount of movement depends on the elapse time
// from the last frame. Hence no matter how fast the
// screen is updated, the amount of movement will just
// be the same
mDistance -= move;
//The remaining distance is reduced after each move

mCharacterNode->translate(mDirection * move);
//If not, translate 。ァmove。ィ amount in "mDirection"

Vector3 characterPos = mCharacterNode->getPosition();
Ray ray(Vector3(characterPos.x, 100000, characterPos.z), Vector3::NEGATIVE_UNIT_Y);

RaySceneQuery *raySceneQuery = mSceneMgr->createRayQuery(ray);

RaySceneQueryResult & qryResult = raySceneQuery->execute();
RaySceneQueryResult::iterator i = qryResult.begin();

//SceneNode* mFireBallNode = mSceneMgr->getSceneNode("FireBallNode");

if(i != qryResult.end() && i->worldFragment)
//To make sure that there is something in the vector
//and that element is a world fragment
{
mCharacterNode->setPosition(characterPos.x, i->worldFragment->singleIntersection.y, characterPos.z);
//set the height on the object to the intersection point between the ray and the terrain

//mFireBallNode->setPosition(mFireBallNode->getPosition().x, i->worldFragment->singleIntersection.y, mFireBallNode->getPosition().z);
}

//add explosion code



//if(mFireBallDirection != Vector3::ZERO)
//{
//// Real move = mWalkSpeed * evt.timeSinceLastFrame;
// //so the moving speed of the fireball is related to the walking speed

// //how to let the fireball know it arrives the destination<-- no need
// mFireBallNode->translate(mFireBallDirection * move *10.0f);
// mFireBallDistance -= move * 10.0f;

// if(mFireBallDistance <= 0.0f)
// {
// mFireBallNode->setVisible(false);

// Entity* mCharacterEntity = mSceneMgr->getEntity("Character");
// if(mAnimationState)
// mAnimationState->setEnabled(false);
// mAnimationState = mCharacterEntity->getAnimationState("Die");

// mAnimationState->setEnabled(true);
// mAnimationState->setLoop(false);

// robotMove = false;
// mFireBallDirection = Vector3::ZERO;

// }//endif

//}//end if

}//end else if
mExplosionCountdown -= evt.timeSinceLastFrame;

if (mExplosionCountdown < 0 && mExplosionParticle != NULL)
{
mExplosionNode->detachObject("Explosion");
mSceneMgr->destroyParticleSystem(mExplosionParticle);
mExplosionParticle = NULL;
}

FMOD_RESULT result;
mKeyboard->capture();
if (mKeyboard->isKeyDown(OIS::KC_Y) && mKeyBuffer <= 0)
{
result = mSoundSystem->playSound(FMOD_CHANNEL_FREE, mSound2d, false, &mChannel);
mChannel->setVolume(0.25); // Set the volume to 25% of the maximum
mKeyBuffer = 0.3; // Will not call playSound() within 0.3sec
}

if (mKeyboard->isKeyDown(OIS::KC_B) && mKeyBuffer <= 0)
{
mChannel->stop();
mKeyBuffer = 0.3;
}

if (mKeyboard->isKeyDown(OIS::KC_T) && mKeyBuffer <= 0)
{
mCamera->setPosition(1475, 400, 1700);
mCamera->lookAt(mCharacterNode->getPosition());
}

if (mKeyboard->isKeyDown(OIS::KC_V) && mKeyBuffer <= 0)
{
mCamera->setPosition(1475, 250, 1700);
mCamera->lookAt(mCharacterNode->getPosition());
}

mKeyBuffer -= evt.timeSinceLastFrame;


}//end ProcessCaculation


#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif


#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char *argv[])
#endif
{
// Create application object
EIE360ProjectApp app;

try {
app.go();
} catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " <<
e.getFullDescription().c_str() << std::endl;
#endif
}

return 0;
}

#ifdef __cplusplus
}
#endif