//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application60::OnCreateScene(SceneContainer &cContainer)
{
	// Create a camera scene node
	SceneNode *pCameraSceneNode = cContainer.Create("PLScene::SNCamera", "FreeCamera", "Position=\"1 2 -3\" Rotation=\"25 210 0\"");
	if (pCameraSceneNode && pCameraSceneNode->IsInstanceOf("PLScene::SNCamera")) {
		// Make this to our main scene camera
		SetCamera(reinterpret_cast<SNCamera*>(pCameraSceneNode));
	}

	// Create a scene node with the soldier mesh which can produce a shadow
	SceneNode *pSoldierSceneNode = cContainer.Create("PLScene::SNMesh", "Soldier", "Flags=\"CastShadow|ReceiveShadow\" Position=\"0.0 0.1 -5.0\" Scale=\"0.008 0.008 0.008\" Mesh=\"Data/Meshes/Soldier.mesh\"");
	if (pSoldierSceneNode) {
		// Add a scene node modifier which will constantly rotate the soldier
		pSoldierSceneNode->AddModifier("PLScene::SNMRotationLinearAnimation", "Velocity=\"0 10 0\"");

		// Add a scene node modifier which will playback the animation named "walk_0" letting the soldier walk
		pSoldierSceneNode->AddModifier("PLScene::SNMMeshAnimation", "Name=\"walk_0\"");

		// Add a scene node modifier which will animate the morph target named "blink" letting the soldier blink from time to time
		pSoldierSceneNode->AddModifier("PLScene::SNMMeshMorphBlink", "Name=\"blink\"");
	}

	// Create a light source scene node to illuminate the scene - this light can cast shadows
	cContainer.Create("PLScene::SNPointLight", "Light", "Flags=\"CastShadow|Flares|Corona\" Range=\"4\"");

	// Create the floor scene node
	cContainer.Create("PLScene::SNMesh", "Floor", "Flags=\"CastShadow|ReceiveShadow\" Position=\"0.0 0.0 -5.0\" Rotation=\"0.0 180.0 0.0\" Scale=\"4.0 0.1 4.0\" Mesh=\"Default\"");

	// Set scene container
	SetScene(&cContainer);
}
/**
*  @brief
*    Restarts the game
*/
void Application67::Restart()
{
	// Get the scene container
	SceneContainer *pSceneContainer = GetScene();
	if (pSceneContainer) {
		// Clean up your scene container
		pSceneContainer->Clear();

		// Create the camera (we need the camera to control the post processing)
		SceneNode *pCamera = pSceneContainer->Create("PLScene::SNCamera", "FixedCamera");
		if (pCamera && pCamera->IsInstanceOf("PLScene::SNCamera")) {
			// Add a post process scene node modifier from the 'PLPostProcessEffects'-plugin
			pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessOldFilm", "Flags='Inactive'");

			// Make this to our main scene camera
			SetCamera(reinterpret_cast<SNCamera*>(pCamera));
		}

		// Create an UFO from mars attacking the earth :D
		pSceneContainer->Create("SNUFO", "Ufo");

		// Create the gun (the player)
		pSceneContainer->Create("SNGun", "Gun", "Position=\"157 155\"");
	}
}
//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application70::OnCreateScene(SceneContainer &cContainer)
{
	// Create a camera
	SceneNode *pCamera = cContainer.Create("PLScene::SNCamera", "FreeCamera", "Position=\"1 2 -3\" Rotation=\"25 210 0\"");
	if (pCamera && pCamera->IsInstanceOf("PLScene::SNCamera")) {
		// Make this to our main scene camera
		SetCamera(reinterpret_cast<SNCamera*>(pCamera));

		// Add a controller modifier so we can look around the camera by using a default control
		pCamera->AddModifier("PLEngine::SNMEgoLookController");

		// Add a controller modifier so we can move around the camera by using a default control
		pCamera->AddModifier("PLEngine::SNMMoveController");
	}

	// Create the floor
	cContainer.Create("PLScene::SNMesh", "Floor", "Position=\"0 0 -5\" Scale=\"4 0.1 4\" Mesh=\"Default\"");

	// Create an instance of the fire particle effect scene node
	cContainer.Create("SNFireSample", "Fire", "Position=\"0.5 0.3 -5\" Scale=\"0.1 0.1 0.1\"");

	// Create an instance of the basic particle effect scene node
	cContainer.Create("SNBasicSample", "Basic", "Position=\"-0.5 0.1 -8\" Scale=\"0.5 0.5 0.5\"");

	// Create an instance of the gravitation particle effect scene node
	cContainer.Create("SNGravitationSample", "Gravitation", "Position=\"-1 1 -5\" Scale=\"0.5 0.5 0.5\"");

	// Create an instance of the galaxy particle effect scene node
	cContainer.Create("SNGalaxySample", "Galaxy", "Position=\"-3 0.5 -8\" Scale=\"0.5 0.5 0.5\"");

	// Setup scene surface painter
	SurfacePainter *pPainter = GetPainter();
	if (pPainter && pPainter->IsInstanceOf("PLScene::SPScene")) {
		SPScene *pSPScene = static_cast<SPScene*>(pPainter);
		pSPScene->SetRootContainer(cContainer.GetContainer());
		pSPScene->SetSceneContainer(&cContainer);
	}

	// Set scene container
	SetScene(&cContainer);
}
//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application65::OnCreateScene(SceneContainer &cContainer)
{
	// Create a scene node with the soldier mesh
	cContainer.Create("PLScene::SNMesh", "Soldier", "Position=\"0.0 -0.7 -4.0\" Scale=\"0.008 0.008 0.008\" Mesh=\"Data/Meshes/Soldier.mesh\"");

	// Create a nice particle effect behind the soldier
	cContainer.Create("PLParticleGroups::PGMagic2", "Magic2", "Position=\"0.0 0.0 -25.0\"");

	// Create a moving light source to illuminate the scene
	cContainer.Create("PLScene::SNPointLight", "Light", "Position=\"1.0 2.0 -2.0\" Flags=\"Flares|Corona|Blend\" Range=\"15.0\"");

	// Create a camera - this time we increase the camera FOV to get a better space feeling :)
	SceneNode *pCamera = cContainer.Create("PLScene::SNCamera", "FixedCamera", "Position=\"0.0 0.0 -2.5\" Rotation=\"0.0 180.0 0.0\" FOV=\"60\"");
	if (pCamera && pCamera->IsInstanceOf("PLScene::SNCamera")) {
		// Make this to our main scene camera
		SetCamera(reinterpret_cast<SNCamera*>(pCamera));

		// Get class list of all available post process scene node modifiers
		m_lstModifierClasses.Clear();
		ClassManager::GetInstance()->GetClasses(m_lstModifierClasses, "PLCompositing::SNMPostProcess", Recursive, NoBase, NoAbstract);

		// 'Activate' the first effect
		if (m_lstModifierClasses.GetNumOfElements())
			pCamera->AddModifier(m_lstModifierClasses[m_nCurrentSelectedModifier]->GetClassName());
	}

	// Setup scene surface painter
	SurfacePainter *pPainter = GetPainter();
	if (pPainter && pPainter->IsInstanceOf("PLScene::SPScene")) {
		SPScene *pSPScene = static_cast<SPScene*>(pPainter);
		pSPScene->SetRootContainer(cContainer.GetContainer());
		pSPScene->SetSceneContainer(&cContainer);
	}

	// Within the parent container...
	SceneContainer *pContainer = cContainer.GetContainer();
	if (pContainer) {
		// Add our information text scene nodes
		SceneNode *pInfoText = pContainer->Create("PLScene::SceneContainer", "InfoText", "Flags=\"NoCulling\"");
		if (pInfoText && pInfoText->IsInstanceOf("PLScene::SceneContainer")) {
			SceneContainer *pInfoTextContainer = static_cast<SceneContainer*>(pInfoText);
			pInfoTextContainer->Create("PLScene::SNText2D", '0', "Position=\"0.01 0.01\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("'F1'        = Show/hide this help text")       + '\"');
			pInfoTextContainer->Create("PLScene::SNText2D", '1', "Position=\"0.01 0.03\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("'Space'     = Enable/disable post processing") + '\"');
			pInfoTextContainer->Create("PLScene::SNText2D", '2', "Position=\"0.01 0.05\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("'1-7'       = Custom post process effects")    + '\"');
			pInfoTextContainer->Create("PLScene::SNText2D", '3', "Position=\"0.01 0.07\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("'Page up'   = Next post process effect")       + '\"');
			pInfoTextContainer->Create("PLScene::SNText2D", '4', "Position=\"0.01 0.09\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("'Page down' = Previous post process effect")   + '\"');
		}
	}

	// Set scene container
	SetScene(&cContainer);
}
//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application64::OnCreateScene(SceneContainer &cContainer)
{
	// Create a camera
	SceneNode *pCamera = cContainer.Create("PLScene::SNCamera", "FreeCamera", "Position=\"1 2 -3\" Rotation=\"25 210 0\"");
	if (pCamera && pCamera->IsInstanceOf("PLScene::SNCamera")) {
		// Make this to our main scene camera
		SetCamera(reinterpret_cast<SNCamera*>(pCamera));
	}

	// Create a scene node with the soldier mesh - in debug mode, show some fancy technical visualizations
	SceneNode *pSceneNode = cContainer.Create("PLScene::SNMesh", "Soldier", "Position=\"0.0 0.1 -5.0\" Scale=\"0.008 0.008 0.008\" Mesh=\"Data/Meshes/Soldier.mesh\" DebugFlags=\"DebugShowWireframe|DebugShowJoints|DebugShowJointNames|DebugShowSkeleton\"");
	if (pSceneNode) {
		// Rotate the soldier
		pSceneNode->AddModifier("PLScene::SNMRotationLinearAnimation", "Velocity=\"0 10 0\"");

		// Playback the animation named "walk_0" letting the soldier walk
		pSceneNode->AddModifier("PLScene::SNMMeshAnimation", "Name=\"walk_0\"");

		// Animate the morph target named "blink" letting the soldier blink from time to time
		pSceneNode->AddModifier("PLScene::SNMMeshMorphBlink", "Name=\"blink\"");
	}

	// Create the floor
	cContainer.Create("PLScene::SNMesh", "Floor", "Position=\"0.0 0.0 -5.0\" Rotation=\"0.0 180.0 0.0\" Scale=\"4.0 0.1 4.0\" Mesh=\"Default\"");

	// Setup scene surface painter
	SurfacePainter *pPainter = GetPainter();
	if (pPainter && pPainter->IsInstanceOf("PLScene::SPScene")) {
		SPScene *pSPScene = static_cast<SPScene*>(pPainter);
		pSPScene->SetRootContainer(cContainer.GetContainer());
		pSPScene->SetSceneContainer(&cContainer);
	}

	// Set scene container
	SetScene(&cContainer);

	// Create the picking component
	m_pMyPicking = new MyPicking(*this);
}
//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application61::OnCreateScene(SceneContainer &cContainer)
{
	// Set no scene container as default
	SetScene(nullptr);

	// Sound API given?
	if (m_sSoundAPI.GetLength()) {
		// Create a scene container with our 'concrete sound scene' using the chosen sound API
		SceneNode *pSceneContainerNode = cContainer.Create("PLSound::SCSound", "SoundScene", "SoundAPI=\"" + m_sSoundAPI + "\" Pitch=\"" + Timing::GetInstance()->GetTimeScaleFactor() + '\"');
		if (pSceneContainerNode && pSceneContainerNode->IsInstanceOf("PLScene::SceneContainer")) {
			SceneContainer *pSceneContainer = static_cast<SceneContainer*>(pSceneContainerNode);

			// Protect this important container!
			pSceneContainer->SetProtected(true);

			// Set scene container
			SetScene(pSceneContainer);

			// Populate the scene container
			// Create a camera
			SceneNode *pCamera = pSceneContainer->Create("PLScene::SNCamera", "FreeCamera", "Position=\"0.0 -1.5 1.4\" Rotation=\"-14.0 180.0 0.0\"");
			if (pCamera && pCamera->IsInstanceOf("PLScene::SNCamera")) {
				// Make this to our main scene camera
				SetCamera(reinterpret_cast<SNCamera*>(pCamera));

				// Add a controller modifier so we can look around the camera by using a default control
				pCamera->AddModifier("PLEngine::SNMEgoLookController");

				// Add a controller modifier so we can move around the camera by using a default control
				pCamera->AddModifier("PLEngine::SNMMoveController", "Speed=\"2\"");

				// Make this camera to the 'sound listener'
				pSceneContainer->SetAttribute("Listener", pCamera->GetName());
			}

			// Create the floor
			pSceneContainer->Create("PLScene::SNMesh", "Floor", "Position=\"0.0 -2.1 -5.0\" Rotation=\"0.0 180.0 0.0\" Scale=\"4.0 0.1 4.0\" Mesh=\"Default\"");

			// Create a box on the floor
			pSceneContainer->Create("PLScene::SNMesh", "Box", "Position=\"0.0 -1.5 -5.0\" Scale=\"0.5 0.5 0.5\" Mesh=\"Default\"");

			// Create rain particles and rain sound
			pSceneContainer->Create("PLParticleGroups::PGRain", "Rain", "Position=\"0.0 15.0 -5.0\" Flags=\"ForceUpdate\" MediumSize=\"3\"");
			pSceneContainer->Create("PLSound::SNSound", "RainSound", "Sound=\"Data/Sounds/Rain.ogg\" Volume=\"0.2\"");

			// Create the soldier walking in the rain :)
			SceneNode *pSoldier = pSceneContainer->Create("PLScene::SNMesh", "Soldier", "Position=\"0.0 -1.5 -5.0\" Scale=\"0.007 0.007 0.007\" Mesh=\"Data/Meshes/Soldier.mesh\"");
			if (pSoldier) {
				// Add animation modifier
				pSoldier->AddModifier("PLScene::SNMMeshAnimation", "Name=\"walk_0\" Speed=\"2\"");

				// Let the soldier walk on a path...
				pSoldier->AddModifier("PLScene::SNMPositionPath", "Filename=\"Data/Misc/61Sound_Soldier.path\" Speed=\"0.5\" Flags=\"NodeIndexProgress\" Interpolation=\"CatmullRomCurve\"");

				// ... and we should look into the direction he's moving
				pSoldier->AddModifier("PLScene::SNMRotationMoveDirection");

				// Link a footsteps sound to the soldier
				pSoldier->AddModifier("PLSound::SNMSound","Sound=\"Data/Sounds/Walking.ogg\"");
			}

			// Setup scene surface painter
			SurfacePainter *pPainter = GetPainter();
			if (pPainter && pPainter->IsInstanceOf("PLScene::SPScene")) {
				SPScene *pSPScene = static_cast<SPScene*>(pPainter);
				pSPScene->SetRootContainer(cContainer.GetContainer());
				pSPScene->SetSceneContainer(pSceneContainer);
			}

			// Within the parent container...
			SceneContainer *pContainer = pSceneContainer->GetContainer();
			if (pContainer) {
				// Get/add our information text scene nodes
				SceneNode *pInfoText = pContainer->Create("PLScene::SceneContainer", "InfoText", "Flags=\"NoCulling\"");
				if (pInfoText && pInfoText->IsInstanceOf("PLScene::SceneContainer")) {
					SceneContainer *pInfoTextContainer = static_cast<SceneContainer*>(pInfoText);

					// The name of the used sound API
					pInfoTextContainer->Create("PLScene::SNText2D", "SoundAPI", "Position=\"0.01 0.01\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("Sound API: ") + GetSoundAPI() + '\"');

					// Draw keys information
					pInfoTextContainer->Create("PLScene::SNText2D", "Keys",      "Position=\"0.01 0.04\" Flags=\"No3DPosition|NoCenter\" Text=\"" + PLT("Keys:")                      + '\"');
					pInfoTextContainer->Create("PLScene::SNText2D", "TimeScale", "Position=\"0.06 0.08\" Flags=\"No3DPosition|NoCenter\"");
					UpdateTimeScaleTextNode();
				}
			}
		}
	}
}
/**
*  @brief
*    Called when a control event has occurred
*/
void Application65::OnControl(Control &cControl)
{
	// Is it a button and was it just hit?
	if (cControl.GetType() == ControlButton && reinterpret_cast<Button&>(cControl).IsHit()) {
		// Check whether the escape key was pressed
		if (cControl.GetName() == "KeyboardEscape") {
			// Shut down the application
			Exit(0);

		// Show/hide the help text
		} else if (cControl.GetName() == "KeyboardF1") {
			// Get the info text scene node
			SceneNode *pSceneNode = GetRootScene() ? GetRootScene()->GetByName("InfoText") : nullptr;
			if (pSceneNode) {
				// Toggle the active state of the scene node
				pSceneNode->SetActive(!pSceneNode->IsActive());
			}

		// Toggle post processing
		} else if (cControl.GetName() == "KeyboardSpace") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Loop through all available post process scene node modifiers
				uint32			   nIndex    = 0;
				SceneNodeModifier *pModifier = pCamera->GetModifier("PLCompositing::SNMPostProcess", nIndex);
				while (pModifier) {
					// Toggle the active state of the post process scene node modifier
					pModifier->SetActive(!pModifier->IsActive());

					// Next modifier, please
					pModifier = pCamera->GetModifier("PLCompositing::SNMPostProcess", ++nIndex);
				}
			}

		// Next post process effect
		} else if (cControl.GetName() == "KeyboardPageUp") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Increase the current selected modifier index
				m_nCurrentSelectedModifier++;
				if (m_nCurrentSelectedModifier >= m_lstModifierClasses.GetNumOfElements())
					m_nCurrentSelectedModifier = 0;

				// Remove all old modifiers add the new one
				pCamera->ClearModifiers();
				pCamera->AddModifier(m_lstModifierClasses[m_nCurrentSelectedModifier]->GetClassName());
			}

		// Previous post process effect
		} else if (cControl.GetName() == "KeyboardPageDown") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Decrease the current selected modifier index
				if (m_nCurrentSelectedModifier)
					m_nCurrentSelectedModifier--;
				else
					m_nCurrentSelectedModifier = m_lstModifierClasses.GetNumOfElements()-1;

				// Remove all old modifiers add the new one
				pCamera->ClearModifiers();
				pCamera->AddModifier(m_lstModifierClasses[m_nCurrentSelectedModifier]->GetClassName());
			}

		// Custom post process effect: "Rainbow"
		} else if (cControl.GetName() == "Keyboard1") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new one
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessCrazyBars", "ColorScaleY=\"0.002\"");
			}

		// Custom post process effect: "Cartoon"
		} else if (cControl.GetName() == "Keyboard2") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new ones
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessEdgeDetect", "LuminanceConvert=\"-0.2125 -0.7154 -0.0721\"");
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessCombineMultiplicate");
			}

		// Custom post process effect: "Animated cartoon"
		} else if (cControl.GetName() == "Keyboard3") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new ones
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessEdgeDetect", "LuminanceConvert=\"-0.2125 -0.7154 -0.0721\"");
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessOldFilm");
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessCombineMultiplicate");
			}

		// Custom post process effect: "Animated old cartoon"
		} else if (cControl.GetName() == "Keyboard4") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new ones
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessEdgeDetect", "LuminanceConvert=\"-0.2125 -0.7154 -0.0721\"");
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessCombineMultiplicate");
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessOldFilm");
			}

		// Custom post process effect: "Scratch"
		} else if (cControl.GetName() == "Keyboard5") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new one
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessEdgeDetect", "LuminanceConvert=\"-0.2125 -0.7154 -0.0721\"");
			}

		// Custom post process effect: "Animated old scratch"
		} else if (cControl.GetName() == "Keyboard6") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new ones
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessEdgeDetect", "LuminanceConvert=\"-0.2125 -0.7154 -0.0721\"");
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessOldFilm");
			}

		// Custom post process effect: "Edge glow"
		} else if (cControl.GetName() == "Keyboard7") {
			// Get the currently used camera
			SceneNode *pCamera = reinterpret_cast<SceneNode*>(GetCamera());
			if (pCamera) {
				// Remove all old modifiers add the new one
				pCamera->ClearModifiers();
				pCamera->AddModifier("PLPostProcessEffects::SNMPostProcessEdgeDetect", "Filename=\"Data/PostProcesses/EdgeGlow.pp\"");
			}
		}
	}
}