From e2d2c0163634cc0819c3d928b17965f4987fed4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lasse=20=C3=96=C3=B6rni?= Date: Sun, 11 Aug 2013 22:24:26 +0000 Subject: [PATCH] Added AnimatingScene sample. --- Source/Samples/04_StaticScene/StaticScene.cpp | 2 +- .../05_AnimatingScene/AnimatingScene.cpp | 201 ++++++++++++++++++ .../05_AnimatingScene/AnimatingScene.h | 70 ++++++ .../Samples/05_AnimatingScene/CMakeLists.txt | 32 +++ Source/Samples/05_AnimatingScene/Rotator.cpp | 62 ++++++ Source/Samples/05_AnimatingScene/Rotator.h | 53 +++++ Source/Samples/CMakeLists.txt | 2 + 7 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 Source/Samples/05_AnimatingScene/AnimatingScene.cpp create mode 100644 Source/Samples/05_AnimatingScene/AnimatingScene.h create mode 100644 Source/Samples/05_AnimatingScene/CMakeLists.txt create mode 100644 Source/Samples/05_AnimatingScene/Rotator.cpp create mode 100644 Source/Samples/05_AnimatingScene/Rotator.h diff --git a/Source/Samples/04_StaticScene/StaticScene.cpp b/Source/Samples/04_StaticScene/StaticScene.cpp index 27478f9f0..2d38de15c 100644 --- a/Source/Samples/04_StaticScene/StaticScene.cpp +++ b/Source/Samples/04_StaticScene/StaticScene.cpp @@ -170,7 +170,7 @@ void StaticScene::MoveCamera(float timeStep) pitch_ += MOUSE_SENSITIVITY * mouseMove.y_; pitch_ = Clamp(pitch_, -90.0f, 90.0f); - // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero. + // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f)); // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed diff --git a/Source/Samples/05_AnimatingScene/AnimatingScene.cpp b/Source/Samples/05_AnimatingScene/AnimatingScene.cpp new file mode 100644 index 000000000..0f5f393b7 --- /dev/null +++ b/Source/Samples/05_AnimatingScene/AnimatingScene.cpp @@ -0,0 +1,201 @@ +// +// Copyright (c) 2008-2013 the Urho3D project. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#include "Engine.h" +#include "Camera.h" +#include "CoreEvents.h" +#include "Font.h" +#include "Graphics.h" +#include "Input.h" +#include "Material.h" +#include "Model.h" +#include "Octree.h" +#include "Renderer.h" +#include "ResourceCache.h" +#include "Rotator.h" +#include "StaticModel.h" +#include "Text.h" +#include "UI.h" +#include "Zone.h" + +#include "AnimatingScene.h" + +#include "DebugNew.h" + +// Expands to this example's entry-point +DEFINE_APPLICATION_MAIN(AnimatingScene) + +AnimatingScene::AnimatingScene(Context* context) : + Sample(context), + yaw_(0.0f), + pitch_(0.0f) +{ + // Register an object factory for our custom Rotator component so that we can create them to scene nodes + context->RegisterFactory(); +} + +void AnimatingScene::Start() +{ + // Execute base class startup + Sample::Start(); + + // Create the scene content + CreateScene(); + + // Create the UI content + CreateInstructions(); + + // Setup the viewport for displaying the scene + SetupViewport(); + + // Hook up to the frame update events + SubscribeToEvents(); +} + +void AnimatingScene::CreateScene() +{ + ResourceCache* cache = GetSubsystem(); + + scene_ = new Scene(context_); + + // Create the Octree component to the scene so that drawable objects can be rendered. Use default volume + // (-1000, -1000, -1000) to (1000, 1000, 1000) + scene_->CreateComponent(); + + // Create a Zone component into a child scene node. The Zone controls ambient lighting and fog settings. Like the Octree, + // it also defines its volume with a bounding box, but can be rotated (so it does not need to be aligned to the world X, Y + // and Z axes.) Drawable objects "pick up" the zone they belong to and use it when rendering; several zones can exist + Node* zoneNode = scene_->CreateChild("Zone"); + Zone* zone = zoneNode->CreateComponent(); + // Set same volume as the Octree, set a close bluish fog and some ambient light + zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f)); + zone->SetAmbientColor(Color(0.05f, 0.1f, 0.15f)); + zone->SetFogColor(Color(0.1f, 0.2f, 0.3f)); + zone->SetFogStart(10.0f); + zone->SetFogEnd(100.0f); + + // Create randomly positioned and oriented box StaticModels in the scene + const unsigned NUM_OBJECTS = 2000; + for (unsigned i = 0; i < NUM_OBJECTS; ++i) + { + Node* boxNode = scene_->CreateChild("Box"); + StaticModel* boxObject = boxNode->CreateComponent(); + boxNode->SetPosition(Vector3(Random(200.0f) - 100.0f, Random(200.0f) - 100.0f, Random(200.0f) - 100.0f)); + // Orient using random pitch, yaw and roll Euler angles + boxNode->SetRotation(Quaternion(Random(360.0f), Random(360.0f), Random(360.0f))); + boxObject->SetModel(cache->GetResource("Models/Box.mdl")); + boxObject->SetMaterial(cache->GetResource("Materials/Stone.xml")); + // Add our custom Rotator component which will rotate the scene node each frame, when the scene sends its update event. + // Simply set same rotation speed for all objects + Rotator* rotator = boxNode->CreateComponent(); + rotator->SetRotationSpeed(Vector3(10.0f, 20.0f, 30.0f)); + } + + // Create a scene node for the camera, which we will move around. Let the starting position be at the world origin. + // As the fog limits maximum visible distance, we can bring the far clip plane closer for more effective culling + // of distant objects + cameraNode_ = scene_->CreateChild("Camera"); + Camera* camera = cameraNode_->CreateComponent(); + camera->SetFarClip(100.0f); + + // Create a point light to the camera scene node + Light* light = cameraNode_->CreateComponent(); + light->SetLightType(LIGHT_POINT); + light->SetRange(30.0f); +} + +void AnimatingScene::CreateInstructions() +{ + ResourceCache* cache = GetSubsystem(); + UI* ui = GetSubsystem(); + + // Construct new Text object, set string to display and font to use + Text* instructionText = ui->GetRoot()->CreateChild(); + instructionText->SetText("Use WASD keys and mouse to move"); + instructionText->SetFont(cache->GetResource("Fonts/Anonymous Pro.ttf"), 15); + + // Position the text relative to the screen center + instructionText->SetHorizontalAlignment(HA_CENTER); + instructionText->SetVerticalAlignment(VA_CENTER); + instructionText->SetPosition(0, ui->GetRoot()->GetHeight() / 4); +} + +void AnimatingScene::SetupViewport() +{ + Renderer* renderer = GetSubsystem(); + + // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen + SharedPtr viewport(new Viewport(context_, scene_, cameraNode_->GetComponent())); + renderer->SetViewport(0, viewport); +} + +void AnimatingScene::MoveCamera(float timeStep) +{ + // Do not move if the UI has a focused element (the console) + UI* ui = GetSubsystem(); + if (ui->GetFocusElement()) + return; + + Input* input = GetSubsystem(); + + // Movement speed as world units per second + const float MOVE_SPEED = 20.0f; + // Mouse sensitivity as degrees per pixel + const float MOUSE_SENSITIVITY = 0.1f; + + // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees + IntVector2 mouseMove = input->GetMouseMove(); + yaw_ += MOUSE_SENSITIVITY * mouseMove.x_; + pitch_ += MOUSE_SENSITIVITY * mouseMove.y_; + pitch_ = Clamp(pitch_, -90.0f, 90.0f); + + // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero + cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f)); + + // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed + if (input->GetKeyDown('W')) + cameraNode_->TranslateRelative(Vector3::FORWARD * MOVE_SPEED * timeStep); + if (input->GetKeyDown('S')) + cameraNode_->TranslateRelative(Vector3::BACK * MOVE_SPEED * timeStep); + if (input->GetKeyDown('A')) + cameraNode_->TranslateRelative(Vector3::LEFT * MOVE_SPEED * timeStep); + if (input->GetKeyDown('D')) + cameraNode_->TranslateRelative(Vector3::RIGHT * MOVE_SPEED * timeStep); +} + +void AnimatingScene::SubscribeToEvents() +{ + // Subscribes HandleUpdate() method for processing update events + SubscribeToEvent(E_UPDATE, HANDLER(AnimatingScene, HandleUpdate)); +} + +void AnimatingScene::HandleUpdate(StringHash eventType, VariantMap& eventData) +{ + // Event parameters are always defined inside a namespace corresponding to the event's name + using namespace Update; + + // Take the frame time step, which is stored as a float + float timeStep = eventData[P_TIMESTEP].GetFloat(); + + // Move the camera, scale movement with time step + MoveCamera(timeStep); +} diff --git a/Source/Samples/05_AnimatingScene/AnimatingScene.h b/Source/Samples/05_AnimatingScene/AnimatingScene.h new file mode 100644 index 000000000..1733b2929 --- /dev/null +++ b/Source/Samples/05_AnimatingScene/AnimatingScene.h @@ -0,0 +1,70 @@ +// +// Copyright (c) 2008-2013 the Urho3D project. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +#include "Sample.h" +#include "Scene.h" + +// All Urho3D classes reside in namespace Urho3D +using namespace Urho3D; + +/// Animating 3D scene example. +/// This sample demonstrates: +/// - Creating a 3D scene and using a custom component to animate the objects; +/// - Controlling scene ambience with the Zone component; +/// - Attaching a light to an object (the camera); +class AnimatingScene : public Sample +{ + // Mandatory when deriving from Object, enables type information + OBJECT(AnimatingScene) + +public: + /// Construct. + AnimatingScene(Context* context); + + /// Setup after engine initialization and before running the main loop. + virtual void Start(); + +private: + /// Constructs the scene content. + void CreateScene(); + /// Constructs an instruction text to the UI. + void CreateInstructions(); + /// Sets up a viewport for displaying the scene. + void SetupViewport(); + /// Reads input and moves the camera. + void MoveCamera(float timeStep); + /// Subscribe to application-wide logic update events. + void SubscribeToEvents(); + /// Callback method invoked when a logic update event is dispatched. + void HandleUpdate(StringHash eventType, VariantMap& eventData); + + /// Scene. + SharedPtr scene_; + /// Camera scene node. + SharedPtr cameraNode_; + /// Camera yaw angle. + float yaw_; + /// Camera pitch angle. + float pitch_; +}; diff --git a/Source/Samples/05_AnimatingScene/CMakeLists.txt b/Source/Samples/05_AnimatingScene/CMakeLists.txt new file mode 100644 index 000000000..791f6c499 --- /dev/null +++ b/Source/Samples/05_AnimatingScene/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2008-2013 the Urho3D project. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +# Define target name +set (TARGET_NAME 05_AnimatingScene) + +# Define source files +file (GLOB CPP_FILES *.cpp) +file (GLOB H_FILES *.h) +set (SOURCE_FILES ${CPP_FILES} ${H_FILES} ${COMMON_SAMPLE_H_FILES}) + +# Setup target with resource copying +setup_main_executable () diff --git a/Source/Samples/05_AnimatingScene/Rotator.cpp b/Source/Samples/05_AnimatingScene/Rotator.cpp new file mode 100644 index 000000000..3b2e6c328 --- /dev/null +++ b/Source/Samples/05_AnimatingScene/Rotator.cpp @@ -0,0 +1,62 @@ +// +// Copyright (c) 2008-2013 the Urho3D project. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#include "Rotator.h" +#include "Scene.h" +#include "SceneEvents.h" + +Rotator::Rotator(Context* context) : + Component(context), + rotationSpeed_(Vector3::ZERO) +{ +} + +void Rotator::SetRotationSpeed(const Vector3& speed) +{ + rotationSpeed_ = speed; +} + +void Rotator::OnNodeSet(Node* node) +{ + // If the node pointer is nonzero, this component has been created into a scene node. Subscribe to the variable timestep + // scene update event now. If the node pointer is zero, the component is being removed from a scene node at destruction + // time. In that case we do nothing + if (node) + { + Scene* scene = node->GetScene(); + // The scene pointer will be nonzero if the scene node belongs to a scene (it is also legal to create free-standing + // scene nodes) + if (scene) + SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(Rotator, HandleSceneUpdate)); + } +} + +void Rotator::HandleSceneUpdate(StringHash eventType, VariantMap& eventData) +{ + // Get the timestep from the update event + using namespace SceneUpdate; + float timeStep = eventData[P_TIMESTEP].GetFloat(); + + // Components have their scene node as a member variable for convenient access. Rotate the scene node now: construct a + // rotation quaternion from Euler angles, scale rotation speed with the scene update time step + node_->Rotate(Quaternion(rotationSpeed_.x_ * timeStep, rotationSpeed_.y_ * timeStep, rotationSpeed_.z_ * timeStep)); +} diff --git a/Source/Samples/05_AnimatingScene/Rotator.h b/Source/Samples/05_AnimatingScene/Rotator.h new file mode 100644 index 000000000..73950cd0c --- /dev/null +++ b/Source/Samples/05_AnimatingScene/Rotator.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2008-2013 the Urho3D project. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +#include "Component.h" + +// All Urho3D classes reside in namespace Urho3D +using namespace Urho3D; + +/// Custom component for rotating a scene node. +class Rotator : public Component +{ +public: + /// Construct. + Rotator(Context* context); + + /// Set rotation speed about the Euler axes. Will be scaled with scene update time step. + void SetRotationSpeed(const Vector3& speed); + + /// Return rotation speed. + const Vector3& GetRotationSpeed() const { return rotationSpeed_; } + +protected: + /// Handle node being assigned. + virtual void OnNodeSet(Node* node); + +private: + /// Handle scene update event. + void HandleSceneUpdate(StringHash eventType, VariantMap& eventData); + + /// Rotation speed. + Vector3 rotationSpeed_; +}; diff --git a/Source/Samples/CMakeLists.txt b/Source/Samples/CMakeLists.txt index 7a50cba37..a848dce70 100644 --- a/Source/Samples/CMakeLists.txt +++ b/Source/Samples/CMakeLists.txt @@ -41,3 +41,5 @@ add_subdirectory (01_HelloWorld) add_subdirectory (02_HelloGUI) add_subdirectory (03_Sprites) add_subdirectory (04_StaticScene) +add_subdirectory (05_AnimatingScene) +