Пример #1
0
/**
*  @brief
*    Performs picking by using the given line start and end positions
*/
bool Picking::PerformPicking(PickingResult &cPickingResult, SceneContainer &cContainer, const Vector3 &vLineStartPos, const Vector3 &vLineEndPos, Cull::Enum nCull)
{
	// Initialize the picking result
	m_pPickingResult = &cPickingResult;
	cPickingResult.m_pSceneNode				 = nullptr;
	cPickingResult.m_nGeometry				 = 0;
	cPickingResult.m_nTriangle				 = 0;
	cPickingResult.m_vPoint					 = Vector3::Zero;
	cPickingResult.m_pSceneContainer		 = &cContainer;
	cPickingResult.m_vLineStartPos			 = vLineStartPos;
	cPickingResult.m_fNearestSquaredDistance = -1.0f;

	// Trace line
	SQLine *pQuery = static_cast<SQLine*>(cContainer.CreateQuery("PLScene::SQLine"));
	if (pQuery) {
		pQuery->SignalSceneNode.Connect(EventHandlerSceneNode);
		pQuery->GetLine().Set(vLineStartPos, vLineEndPos);
		pQuery->SetCull(nCull);
		pQuery->PerformQuery();
		cContainer.DestroyQuery(*pQuery);
	}

	// Was something picked?
	if (cPickingResult.m_pSceneNode) {
		// Ensure that the picking distance is not greater than the possible maximum
		if ((vLineEndPos-vLineStartPos).GetSquaredLength() >= cPickingResult.m_fNearestSquaredDistance)
			return (cPickingResult.m_pSceneNode != nullptr);
	}

	// Nothing (in range) was picked
	return false;
}
Пример #2
0
/**
*  @brief
*    Loads/reloads the sound
*/
void SNMSound::Load()
{
	// Destroy currently used sound source
	Source *pSS = static_cast<Source*>(m_pSoundSourceHandler->GetResource());
	if (pSS)
		delete pSS;

	// Get the PL sound container this scene node is in
	SceneContainer *pContainer = GetSceneNode().GetContainer();
	while (pContainer && !pContainer->IsInstanceOf("PLSound::SCSound"))
		pContainer = pContainer->GetContainer();
	if (pContainer) {
		SoundManager *pSoundManager = static_cast<SCSound*>(pContainer)->GetSoundManager();
		if (pSoundManager) {
			Source *pSoundSource = pSoundManager->CreateSoundSource(pSoundManager->CreateSoundBuffer(m_sSound, (GetFlags() & Stream) != 0));
			m_pSoundSourceHandler->SetResource(pSoundSource);
			pSoundSource->SetAttribute(Source::Position, GetSceneNode().GetTransform().GetPosition());
			pSoundSource->SetVolume(m_fVolume);
			pSoundSource->Set2D((GetFlags() & No3D) != 0);
			pSoundSource->SetLooping(!(GetFlags() & NoLoop));
			pSoundSource->SetPitch(m_fPitch);
			pSoundSource->SetReferenceDistance(m_fReferenceDistance);
			pSoundSource->SetMaxDistance(m_fMaxDistance);
			pSoundSource->SetRolloffFactor(m_fRolloffFactor);
			OnPosition();
			if (!(GetFlags() & NoStartPlayback))
				pSoundSource->Play();
		}
	}
}
Пример #3
0
/**
*  @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 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);
}
Пример #5
0
/**
*  @brief
*    Returns the sound container this sound is in
*/
SCSound *SNMSound::GetSoundContainer() const
{
	// Get the PL sound container this scene node is in
	SceneContainer *pContainer = GetSceneNode().GetContainer();
	while (pContainer && !pContainer->IsInstanceOf("PLSound::SCSound"))
		pContainer = pContainer->GetContainer();

	// Done
	return (pContainer && pContainer->IsInstanceOf("PLSound::SCSound")) ? static_cast<SCSound*>(pContainer) : nullptr;
}
Пример #6
0
//[-------------------------------------------------------]
//[ Protected virtual PLFrontendQt::QPLSceneContext functions ]
//[-------------------------------------------------------]
void MySceneContext::OnCreateScene(SceneContainer &cContainer)
{
	// Create a camera
	SceneNode *pCamera = cContainer.Create("PLScene::SNCamera", "FreeCamera", "Position=\"1 2 -3\" Rotation=\"25 0 0\"");
	if (pCamera && pCamera->IsInstanceOf("PLScene::SNCamera"))
		SetCamera(reinterpret_cast<SNCamera*>(pCamera));

	// 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\"");

	// Set scene container
	SetScene(&cContainer);
}
Пример #7
0
//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application67::OnCreateScene(SceneContainer &cContainer)
{
	// Create a scene container with our 'concrete sound scene' using the default sound API
	SceneNode *pSceneContainerNode = cContainer.Create("PLSound::SCSound", "SoundScene");
	if (pSceneContainerNode && pSceneContainerNode->IsInstanceOf("PLScene::SceneContainer")) {
		SceneContainer *pSceneContainer = static_cast<SceneContainer*>(pSceneContainerNode);

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

		// Populate the scene container
		// 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);

			// Get the scene context
			SceneContext *pSceneContext = GetSceneContext();
			if (pSceneContext) {
				// Create us a scene renderer
				SceneRenderer *pSceneRenderer = pSceneContext->GetSceneRendererManager().Create("2DGame");
				if (pSceneRenderer) {
					// Add begin scene renderer pass
					pSceneRenderer->Create("PLCompositing::SRPBegin", "Begin", "TextureFormat=\"R8G8B8A8\" Flags=\"Inactive\"");

					// Add our own scene renderer pass
					pSceneRenderer->Create("SRP2DGame", "2DGame");

					// Add post processing scene renderer pass
					pSceneRenderer->Create("PLCompositing::SRPPostProcessing", "PostProcessing");

					// Add end scene renderer pass
					pSceneRenderer->Create("PLCompositing::SRPEnd", "End");

					// Make this scene renderer to the default scene renderer of our scene surface painter
					pSPScene->SetDefaultSceneRenderer(pSceneRenderer->GetName());
				}
			}
		}

		// Set scene container
		SetScene(pSceneContainer);

		// Start the game
		Restart();
	}
}
/**
*  @brief
*    Updates the text of the time scale text node
*/
void Application61::UpdateTimeScaleTextNode()
{
	// Get the scene
	SceneContainer *pSceneContainer = GetScene();
	if (pSceneContainer) {
		// Get the scene info text container
		SceneContainer *pInfoTextContainer = static_cast<SceneContainer*>(pSceneContainer->GetByName("Parent.InfoText"));
		if (pInfoTextContainer) {
			// Get the time scale text scene node
			SceneNode *pInfoTextNode = pInfoTextContainer->GetByName("TimeScale");
			if (pInfoTextNode)
				pInfoTextNode->SetAttribute("Text", PLT("1/2/0=Decrease/increase/reset timescale (current: ") + Timing::GetInstance()->GetTimeScaleFactor() + ')');
		}
	}
}
Пример #9
0
/**
*  @brief
*    Returns the target position within the container space of the owner node
*/
bool SNMRotationTarget::GetTargetPosition(Vector3 &vPos) const
{
	// Target scene node given?
	if (Target.Get().GetLength()) {
		// Get the target scene node
		const SceneNode *pTarget;
		if (GetSceneNode().GetContainer())
			pTarget = GetSceneNode().GetContainer()->GetByName(Target.Get());
		else {
			// This must be the root :()
			pTarget = static_cast<const SceneContainer&>(GetSceneNode()).GetByName(Target.Get());
		}
		if (pTarget) {
			// Set the position of the attached node
			vPos = pTarget->GetTransform().GetPosition();

			// Are we in luck and the target is within the same container as the owner node?
			if (GetSceneNode().GetContainer() != pTarget->GetContainer()) {
				// Nope, we have to translate the position into the correct space :(
				SceneContainer *pContainer = pTarget->GetContainer();
				while (pContainer) {
					vPos *= pContainer->GetTransform().GetMatrix();
					pContainer = pContainer->GetContainer();
				}

				// To container space of the owner node
				pContainer = GetSceneNode().GetContainer();
				Stack<SceneContainer*> lstStack;
				while (pContainer) {
					lstStack.Push(pContainer);
					pContainer = pContainer->GetContainer();
				}
				while (lstStack.GetNumOfElements()) {
					pContainer = lstStack.Top();
					lstStack.Pop();
					vPos *= pContainer->GetTransform().GetInverseMatrix();
				}
			}

			// Done
			return true;
		}
	}

	// Error - no valid target scene node, no target rotation :(
	return false;
}
Пример #10
0
/**
*  @brief
*    Clears the scene, after calling this method the scene is empty
*/
void EngineApplication::ClearScene()
{
	// Get the scene container holding our scene
	SceneContainer *pContainer = GetScene();
	if (pContainer) {
		// Clear the old scene
		pContainer->Clear();

		// Cleanup the scene context right now to ensure that all 'delete this'-marked scene nodes are really gone!
		// If this is not done, we may get problems with for example the names of dynamic textures because there may
		// occur name conflicts if multiple render-to-texture scene containers want to render into a same named texture...
		// Topics like 'the new scene is using resources that are already loaded in' must be handled on another level, e.g.
		// by delaying the unloading of currently unreferenced resources.
		if (m_pSceneContext)
			m_pSceneContext->Cleanup();
	}
}
Пример #11
0
/**
*  @brief
*    Returns the gravity vector
*/
Vector3 PGPhysics::GetGravity() const
{
	// Get the PL physics world this scene node is in
	SceneContainer *pContainer = GetContainer();
	while (pContainer && !pContainer->IsInstanceOf("PLPhysics::SCPhysicsWorld"))
		pContainer = pContainer->GetContainer();

	// Get the gravity vector
	Vector3 vGravity;
	if (pContainer && static_cast<SCPhysicsWorld*>(pContainer)->GetWorld())
		static_cast<SCPhysicsWorld*>(pContainer)->GetWorld()->GetGravity(vGravity);
	else
		vGravity.SetXYZ(0.0f, -9.81f, 0.0f);

	// Return the gravity vector
	return vGravity;
}
Пример #12
0
//[-------------------------------------------------------]
//[ Private virtual PLEngine::EngineApplication functions ]
//[-------------------------------------------------------]
void Application66::OnCreateScene(SceneContainer &cContainer)
{
	// Set scene container flags
	cContainer.SetFlags(SceneNode::NoCulling);

	// 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) {
		// Create a 'ingame'-GUI scene node
		const SNGui *pGuiSceneNode = static_cast<SNGui*>(pContainer->Create("PLFrontendPLGui::SNGui", "GUI"));
		if (pGuiSceneNode) {
			// Setup the GUI
			Gui *pGui = pGuiSceneNode->GetGui();
			if (pGui) {
				// Create the GUI font
				if (!GuiFont) {
					GuiFont = new Font(*pGui);
					GuiFont->LoadFromFile("Data/Fonts/LinLibertine_Re-2.7.9.9.otf", 18);
				}

				// Set GUI options
				pGui->SetMouseVisible(false);

				// Create ingame GUI container
				m_pIngameGui = new IngameGui(*this, pGui->GetRootWidget());
				m_pIngameGui->SetSize(Vector2i(1024, 768));
				m_pIngameGui->SetBackgroundColor(PLGraphics::Color4::Transparent);
				m_pIngameGui->SetFocus();
				m_pIngameGui->SetVisible(true);
			}
		}
	}

	// Set scene container
	SetScene(&cContainer);
}
/**
*  @brief
*    Called when a control event has occurred
*/
void Application61::OnControl(Control &cControl)
{
	// Is it a button?
	if (cControl.GetType() == ControlButton && static_cast<Button&>(cControl).IsPressed()) {
		// Check whether the escape key was pressed
		if (cControl.GetName() == "KeyboardEscape") {
			// Shut down the application
			Exit(0);
		} else {
			// Get current time difference
			Timing *pTimer = Timing::GetInstance();
			const float fTimeScaleFactor = pTimer->GetTimeScaleFactor();

			// Check button
			if (cControl.GetName() == "Keyboard1") {
				// Decrease timescale
				pTimer->SetTimeScaleFactor(fTimeScaleFactor - 0.1f);
				if (pTimer->GetTimeScaleFactor() < 0.1f)
					pTimer->SetTimeScaleFactor(0.1f);
			} else if (cControl.GetName() == "Keyboard2") {
				// Increase timescale
				pTimer->SetTimeScaleFactor(fTimeScaleFactor +  0.1f);
				if (pTimer->GetTimeScaleFactor() > 4.0f)
					pTimer->SetTimeScaleFactor(4.0f);
			} else if (cControl.GetName() == "Keyboard3") {
				// Reset timescale
				pTimer->SetTimeScaleFactor();
			}

			// Time scale factor changed?
			if (fTimeScaleFactor != pTimer->GetTimeScaleFactor()) {
				// Update the time scale text node
				UpdateTimeScaleTextNode();

				// Update the pitch variable of the sound container using the time scale factor
				SceneContainer *pSceneContainer = GetScene();
				if (pSceneContainer)
					pSceneContainer->SetAttribute("Pitch", pTimer->GetTimeScaleFactor());
			}
		}
	}
}
Пример #14
0
/**
*  @brief
*    Post draw all scene nodes recursive
*/
void SPScene::DrawPost(Renderer &cRenderer, SceneContainer &cContainer)
{
	// Get the scene container (can be a null pointer)
	SceneContainer *pContainer = GetSceneContainer();

	// Draw parent container
	if (&cContainer != pContainer)
		cContainer.DrawPost(cRenderer);

	// Loop through all nodes
	for (uint32 i=0; i<cContainer.GetNumOfElements(); i++) {
		SceneNode *pNode = cContainer.GetByIndex(i);
		if (pNode != pContainer && pNode->IsVisible() && (pNode->GetDrawFunctionFlags() & SceneNode::UseDrawPost)) {
			if (pNode->IsContainer())
				DrawPost(cRenderer, static_cast<SceneContainer&>(*pNode));
			else
				pNode->DrawPost(cRenderer);
		}
	}
}
Пример #15
0
/**
*  @brief
*    Returns the default scene renderer
*/
SceneRenderer *SPScene::GetDefaultSceneRenderer() const
{
	// Get/load the scene renderer
	SceneRenderer *pSceneRenderer = m_pDefaultSceneRendererHandler->GetResource();
	if (!pSceneRenderer && m_sDefaultSceneRenderer.GetLength()) {
		// Get the root scene container
		SceneContainer *pRootContainer = GetRootContainer();
		if (pRootContainer) {
			// Get the scene context
			SceneContext *pSceneContext = pRootContainer->GetSceneContext();
			if (pSceneContext) {
				pSceneRenderer = pSceneContext->GetSceneRendererManager().LoadResource(m_sDefaultSceneRenderer);
				m_pDefaultSceneRendererHandler->SetResource(pSceneRenderer);
			}
		}
	}

	// Return the scene renderer
	return pSceneRenderer;
}
Пример #16
0
/**
*  @brief
*    Function that is called to create the application's scene container
*/
void EngineApplication::OnCreateScene(SceneContainer &cContainer)
{
	// [TODO] Load 'm_sSceneFilename' if provided

	// Set scene container flags
	cContainer.SetFlags(SceneNode::NoCulling);

	// 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);
	}

	// Configure scene and set the currently used application camera
	SetCamera(SceneCreator::ConfigureScene(cContainer, "PLEngine::SceneCreatorDefault"));

	// 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);
}
Пример #18
0
//[-------------------------------------------------------]
//[ Protected virtual PLScene::SceneApplication functions ]
//[-------------------------------------------------------]
void EngineApplication::OnCreateRootScene()
{
	// Get the scene context
	SceneContext *pSceneContext = GetSceneContext();
	if (pSceneContext) {
		// First, create the scene root container which holds the scene container with our 'concrete' scene within it
		SceneContainer *pRootContainer = pSceneContext->GetRoot() ? static_cast<SceneContainer*>(pSceneContext->GetRoot()->Create("PLScene::SceneContainer", "RootScene")) : nullptr;
		if (pRootContainer) {
			// Protect this important container!
			pRootContainer->SetProtected(true);

			// Create a scene container with our 'concrete scene'
			SceneNode *pSceneContainerNode = pRootContainer->Create("PLScene::SceneContainer", "Scene");
			if (pSceneContainerNode && pSceneContainerNode->IsInstanceOf("PLScene::SceneContainer")) {
				SceneContainer *pSceneContainer = static_cast<SceneContainer*>(pSceneContainerNode);

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

				// Connect event handler
				if (pSceneContainerNode->IsInstanceOf("PLScene::SceneContainer"))
					static_cast<SceneContainer*>(pSceneContainerNode)->SignalLoadProgress.Connect(EventHandlerLoadProgress);

				// Create the 'concrete scene'
				OnCreateScene(*pSceneContainer);
			}

			// Create scene node for engine information
			SceneNode *pSceneNode = pRootContainer->Create("PLEngine::SNEngineInformation");
			if (pSceneNode)
				pSceneNode->SetActive(m_bEditModeEnabled);

			// Create console scene node - using the console command 'timescale <value>' we
			// can change the scene time (slowdown or accelerate)
			pSceneNode = pRootContainer->Create("PLEngine::SNConsole");
			if (pSceneNode && pSceneNode->GetClass()->IsDerivedFrom("PLEngine::SNConsoleBase")) {
				SNConsoleBase *pConsole = static_cast<SNConsoleBase*>(pSceneNode);

				// Register default commands
				pConsole->RegisterCommand(0,	"quit",		"",	"",	Functor<void, ConsoleCommand &>(&EngineApplication::ConsoleCommandQuit, this));
				pConsole->RegisterCommand(0,	"exit",		"",	"",	Functor<void, ConsoleCommand &>(&EngineApplication::ConsoleCommandQuit, this));
				pConsole->RegisterCommand(0,	"bye",		"",	"",	Functor<void, ConsoleCommand &>(&EngineApplication::ConsoleCommandQuit, this));
				pConsole->RegisterCommand(0,	"logout",	"",	"",	Functor<void, ConsoleCommand &>(&EngineApplication::ConsoleCommandQuit, this));

				// Set active state
				pConsole->SetActive(m_bEditModeEnabled);
			}
		}

		// Set the root scene
		SetRootScene(pRootContainer);
	}
}
Пример #19
0
/**
*  @brief
*    Sets whether or not edit mode is enabled
*/
void EngineApplication::SetEditModeEnabled(bool bEnabled)
{
	// State change?
	if (m_bEditModeEnabled != bEnabled) {
		// Backup the new state
		m_bEditModeEnabled = bEnabled;

		// Get the root scene
		SceneContainer *pRootScene = GetRootScene();
		if (pRootScene) {
			// Enable/disable standard edit features from the PixelLight scene graph (if the user hasn't changed anything :)
			SceneNode *pSceneNode = pRootScene->GetByName("PLEngine::SNEngineInformation0");
			if (pSceneNode)
				pSceneNode->SetActive(bEnabled);
			pSceneNode = pRootScene->GetByName("PLEngine::SNConsole0");
			if (pSceneNode)
				pSceneNode->SetActive(bEnabled);
		}

		// Setup log level
		Log::GetInstance()->SetLogLevel(static_cast<uint8>(m_bEditModeEnabled ? Log::Debug : Log::Info));
	}
}
//[-------------------------------------------------------]
//[ Private virtual PLCore::AbstractFrontend functions    ]
//[-------------------------------------------------------]
void Application60::OnUpdate()
{
	// One important word at the beginning: DON'T COPYCAT THIS!
	// The following is 'just' a simple demonstration how the scene graph 'can' be used. It's
	// definitely not good to update your scene nodes in the way you can see within this function.
	// Its quite to intricate, inflexible and not performant. Use for example a scene node modifier
	// added to your scene node (in this case 'the white light') for this job!

	// Call base implementation
	EngineApplication::OnUpdate();

	// Get the scene container with our 'concrete scene'
	SceneContainer *pSceneContainer = GetScene();
	if (pSceneContainer) {
		// Get the scene node with the name 'Light' (our 'white light')
		SceneNode *pLightSceneNode = pSceneContainer->GetByName("Light");
		if (pLightSceneNode) {
			// This variable is used for the light animation. Its just static you keep the implementation
			// for a good sample overview completely within this function.
			static float fLightTimer = 0.0f;

			// Get a new fancy light position
			const Vector3 vPosition(Math::Sin(fLightTimer), Math::Sin(fLightTimer)/2+2, -(Math::Cos(fLightTimer)+5));

			// We set the current light position using the RTTI class interface. This is quite comfortable and
			// universal because you haven't to care about the concrete class type - just set the variable values.
			pLightSceneNode->SetAttribute("Position", Var<Vector3>(vPosition));	// More efficient
			// Another way by using strings:
			// pLightSceneNode->SetAttribute("Position", vPosition.ToString());	// More generic
			// For highly performance critical situations it's recommend to avoid using these RTTI
			// functions to set your variables and use the concrete provided class interfaces instead.

			// Update the light timer by using the time difference between the last and the current frame
			fLightTimer += Timing::GetInstance()->GetTimeDifference();
		}
	}
}
Пример #21
0
/**
*  @brief
*    Function that is called to create the application's root scene
*/
void SceneApplication::OnCreateRootScene()
{
	// [TODO] Load 'm_sSceneFilename' if provided

	// Is there a scene context?
	if (m_pSceneContext) {
		// First, create the scene root container which holds the scene container with our 'concrete' scene within it
		SceneContainer *pRootContainer = m_pSceneContext->GetRoot() ? static_cast<SceneContainer*>(m_pSceneContext->GetRoot()->Create("PLScene::SceneContainer", "RootScene")) : nullptr;
		if (pRootContainer) {
			// Protect this important container!
			pRootContainer->SetProtected(true);

			// Create a scene container with our 'concrete scene'
			SceneNode *pSceneContainerNode = pRootContainer->Create("PLScene::SceneContainer", "Scene");
			if (pSceneContainerNode && pSceneContainerNode->IsContainer()) {
				// Protect this important container!
				pSceneContainerNode->SetProtected(true);
			}
		}

		// Set the root scene
		SetRootScene(pRootContainer);
	}
}
//[-------------------------------------------------------]
//[ 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);
}
Пример #23
0
bool EngineApplication::LoadScene(const String &sFilename)
{
	// Get the scene container holding our scene
	SceneContainer *pContainer = GetScene();
	if (!pContainer)
		return false; // Error! (should NEVER happen...)

	// Disable the ingame GUI
	SceneNode *pGui = pContainer->GetContainer()->GetByName("GUI");
	if (pGui)
		pGui->SetActive(false);

	// Clear the scene, after calling this method the scene is empty
	ClearScene();

	// Load the scene
	bool bResult = pContainer->LoadByFilename(sFilename);
	if (bResult) {
		// Set a null pointer camera and default scene renderer
		m_sDefaultSceneRenderer		= "";
		m_sSceneRendererVariables	= "";
		m_sClearColor				= "";
		m_sStartCamera				= "";
		m_pFirstFoundCamera			= nullptr;
		m_bHasLoadScreen			= false;

		// Get scene surface painter
		SurfacePainter *pPainter = GetPainter();
		if (pPainter && pPainter->IsInstanceOf("PLScene::SPScene")) {
			// Assign the first found camera scene node to your surface listener and look for
			// known key/value data scene nodes
			SceneQuery *pSceneQuery = pContainer->CreateQuery("PLScene::SQEnumerate");
			if (pSceneQuery) {
				// Connect event handler
				pSceneQuery->SignalSceneNode.Connect(EventHandlerSceneNode);

				// Perform the query
				pSceneQuery->PerformQuery();

				// Destroy the query
				pContainer->DestroyQuery(*pSceneQuery);
			}

			// Set to default scene renderer?
			if (!m_sDefaultSceneRenderer.GetLength())
				m_sDefaultSceneRenderer = DefaultSceneRenderer;

			// Sets all scene renderer pass attribute values to their default value
			GetSceneRendererTool().SetDefaultValues();

			// Set the used scene renderer
			GetSceneRendererTool().SetSceneRenderer(pContainer, m_sDefaultSceneRenderer, DefaultSceneRenderer);

			// Set clear color
			GetSceneRendererTool().SetPassAttribute("Begin", "ColorClear", m_sClearColor);

			// Set scene renderer variables
			if (m_sSceneRendererVariables.GetLength())
				GetSceneRendererTool().SetValues(m_sSceneRendererVariables);

			// Is there a given start camera?
			SceneNode *pCamera = nullptr;
			if (m_sStartCamera.GetLength()) {
				SceneNode *pStartCamera = pContainer->GetByName(m_sStartCamera);
				if (pStartCamera && pStartCamera->IsCamera())
					pCamera = pStartCamera;
			}

			// Use the first found camera?
			if (!pCamera)
				pCamera = m_pFirstFoundCamera;

			// Activate the current used camera by default
			if (pCamera)
				pCamera->SetActive(true);

			// Assign this camera to the scene renderer and to the application
			SetCamera(reinterpret_cast<SNCamera*>(pCamera));
		}

		// Emit the scene loading has been finished successfully event
		SignalSceneLoadingFinished();
	}

	// Enable the ingame GUI
	if (pGui)
		pGui->SetActive(true);

	// Done
	return bResult;
}
Пример #24
0
//[-------------------------------------------------------]
//[ Public virtual PLRenderer::SurfacePainter functions   ]
//[-------------------------------------------------------]
void SPScene::OnPaint(Surface &cSurface)
{
	// Get the used renderer
	Renderer &cRenderer = GetRenderer();

	// Get camera
	SNCamera *pCamera = nullptr;
	SceneRenderer *pSceneRenderer = nullptr;
	if (m_pCameraNodeHandler->GetElement()) {
		pCamera = static_cast<SNCamera*>(m_pCameraNodeHandler->GetElement());
		if (pCamera)
			pSceneRenderer = pCamera->GetSceneRenderer();
	}
	SNCamera::SetCamera(pCamera, &cRenderer);

	// Check the used scene renderer
	if (!pSceneRenderer)
		pSceneRenderer = GetDefaultSceneRenderer();

	// Check the used scene renderer
	if (pSceneRenderer) {
		// Get the root scene container
		SceneContainer *pRootContainer = GetRootContainer();
		if (pRootContainer) {
			// Get the cull query
			SQCull *pCullQuery = static_cast<SQCull*>(m_pCullQuery->GetElement());
			if (pCullQuery) {
				// Set camera (can be a null pointer)
				if (pCamera) {
					// Setup render query
					SceneContainer *pCameraContainer = pCamera->GetContainer();
					pCullQuery->SetCameraContainer((pCameraContainer && pCameraContainer->IsCell()) ? pCameraContainer : nullptr);
					pCullQuery->SetCameraPosition(pCamera->GetTransform().GetPosition());
					pCullQuery->SetViewFrustum(pCamera->GetFrustum(cRenderer.GetViewport()));
					pCullQuery->SetProjectionMatrix(pCamera->GetProjectionMatrix(cRenderer.GetViewport()));
					pCullQuery->SetViewMatrix(pCamera->GetViewMatrix());
					pCullQuery->SetViewProjectionMatrix(pCullQuery->GetProjectionMatrix()*pCamera->GetViewMatrix());
				} else {
					// Set default states
					pCullQuery->SetCameraContainer(nullptr);
					pCullQuery->SetCameraPosition(Vector3::Zero);
					Matrix4x4 mProj;
					mProj.PerspectiveFov(static_cast<float>(90.0f*Math::DegToRad), 1.0f, 0.001f, 10000.0f);
					Frustum cFrustum;
					cFrustum.CreateViewPlanes(mProj, false);
					pCullQuery->SetViewFrustum(cFrustum);
				}

				// Perform the visibility determination
				pCullQuery->PerformQuery();
			}

			// Get the scene container (can be a null pointer)
			SceneContainer *pContainer = GetSceneContainer();

			// Pre all scene nodes
			DrawPre(cRenderer, *pRootContainer);

			// Draw all scene nodes solid
			DrawSolid(cRenderer, *pRootContainer);

			// Draw the scene container (if there's one)
			if (pContainer && pCullQuery)
				pSceneRenderer->DrawScene(cRenderer, *pCullQuery);

			// Draw all scene nodes transparent
			DrawTransparent(cRenderer, *pRootContainer);

			// Debug all scene nodes
			DrawDebug(cRenderer, *pRootContainer);

			// Post all scene nodes
			DrawPost(cRenderer, *pRootContainer);
		}
	}
}
Пример #25
0
/**
*  @brief
*    Returns the used scene context
*/
SceneContext *SPScene::GetSceneContext() const
{
	SceneContainer *pSceneContainer = static_cast<SceneContainer*>(m_pRootContainerHandler->GetElement());
	return pSceneContainer ? pSceneContainer->GetSceneContext() : nullptr;
}
//[-------------------------------------------------------]
//[ 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);
}
Пример #27
0
/**
*  @brief
*    Recursive part of PerformQuery()
*/
bool SQPlaneSet::PerformQueryRec(SceneHierarchyNode &cHierarchyNode)
{
	// Is this scene hierarchy node intersecting the plane set?
	if (!cHierarchyNode.CheckPlaneSet(m_cPlaneSet))
		return true; // Continue the query

	// Touch this node
	cHierarchyNode.Touch();

	// Get the scene context
	SceneContext *pSceneContext = GetSceneContext();
	if (pSceneContext) {
		// Inform all listeners
		const SceneHierarchyNodeItem *pItem = cHierarchyNode.GetFirstItem();
		while (pItem) {
			// Get the linked scene node
			SceneNode *pSceneNode = pItem->GetSceneNode();

			// Was this scene node already processed?
			if (pSceneNode && !pSceneContext->IsNodeTouched(*pSceneNode)) {
				// Check scene node
				const AABoundingBox &cAABB = pSceneNode->GetContainerAABoundingBox();
				if (Intersect::PlaneSetAABox(m_cPlaneSet, cAABB.vMin, cAABB.vMax)) {
					// Touch this node
					pSceneContext->TouchNode(*pSceneNode);

					// Emit signal
					SignalSceneNode(*this, *pSceneNode);
					if (m_nFlags & StopQuery)
						return false; // Stop the query right now

					// Continue recursive?
					if (m_nFlags & Recursive) {
						// Is this a container and is recursion allowed?
						if (pSceneNode->IsContainer() && !(pSceneNode->GetFlags() & SceneContainer::NoRecursion)) {
							// Backup current plane set
							const PlaneSet cPlaneSet = m_cPlaneSet;

							// Transform the plane set into container space
							m_cPlaneSet *= pSceneNode->GetTransform().GetInverseMatrix();

							// Container recursion
							const bool bContinue = PerformQueryRec(static_cast<SceneContainer*>(pSceneNode)->GetHierarchyInstance()->GetRootNode());

							// Restore plane set
							m_cPlaneSet = cPlaneSet;

							// Stop the query right now?
							if (!bContinue)
								return false;

						// Is this a cell-portal?
						} else if (pSceneNode->IsPortal() && pSceneNode->IsInstanceOf("PLScene::SNCellPortal") && !(pSceneNode->GetFlags() & SNCellPortal::NoPassThrough)) {
							// Get the target cell
							SNCellPortal   &cCellPortal	= static_cast<SNCellPortal&>(*pSceneNode);
							SceneContainer *pCell		= reinterpret_cast<SceneContainer*>(cCellPortal.GetTargetCellInstance());
							if (pCell && pCell != pSceneNode->GetContainer()) {
								// Backup current plane set
								const PlaneSet cPlaneSet = m_cPlaneSet;

								// Transform the plane set into container space
								m_cPlaneSet *= cCellPortal.GetWarpMatrix();

								// Container recursion
								const bool bContinue = PerformQueryRec(pCell->GetHierarchyInstance()->GetRootNode());

								// Restore plane set
								m_cPlaneSet = cPlaneSet;

								// Stop the query right now?
								if (!bContinue)
									return false;
							}
						}
					}
				}
			}

			// Next item, please
			pItem = pItem->GetNextItem();
		}
	}

	// Check all sub-hierarchies
	for (uint32 i=0; i<cHierarchyNode.GetNumOfNodes(); i++) {
		if (!PerformQueryRec(*cHierarchyNode.GetNode(i)))
			return false; // Stop the query right now
	}

	// Done, continue the query
	return true;
}
//[-------------------------------------------------------]
//[ 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();
				}
			}
		}
	}
}