diff --git a/res/dist/scripts/sandbox/camera.lua b/res/dist/scripts/sandbox/camera.lua new file mode 100644 index 00000000000..baff8e302d2 --- /dev/null +++ b/res/dist/scripts/sandbox/camera.lua @@ -0,0 +1,27 @@ +local playerCam = Entity("playerCam") + +-- Camera +playerCam.camera = OgreCameraComponent("playerCam") +playerCam:addComponent(playerCam.camera) +-- Scene node +playerCam.sceneNode = OgreSceneNodeComponent() +playerCam:addComponent(playerCam.sceneNode) +-- Transform +playerCam.transform = TransformComponent() +playerCam:addComponent(playerCam.transform) + +playerCam.camera.workingCopy.nearClipDistance = 5 +playerCam.camera:touch() + +playerCam.transform.workingCopy.position.z = 30 +playerCam.transform:touch() + +-- OnUpdate +playerCam.onUpdate = OnUpdateComponent() +playerCam:addComponent(playerCam.onUpdate) +local time = 0 +playerCam.onUpdate.callback = function(entityId, milliseconds) + time = time + milliseconds / 1000 + playerCam.transform.workingCopy.position.z = 25 + 5 * math.sin(time) + playerCam.transform:touch() +end diff --git a/res/dist/scripts/sandbox/light.lua b/res/dist/scripts/sandbox/light.lua index ac097bf756a..8940547341d 100644 --- a/res/dist/scripts/sandbox/light.lua +++ b/res/dist/scripts/sandbox/light.lua @@ -18,7 +18,7 @@ lightEntity = OgreEntityComponent(OgreEntityComponent.PT_SPHERE) light:addComponent(lightEntity) onupdate = OnUpdateComponent() light:addComponent(onupdate) -time = 0 +local time = 0 onupdate.callback = function(entityId, milliseconds) time = time + milliseconds / 1000 light.transform.workingCopy.position.x = 5 * math.sin(time) diff --git a/res/dist/scripts/sandbox/manifest.txt b/res/dist/scripts/sandbox/manifest.txt index a16e4a7c390..88629657233 100644 --- a/res/dist/scripts/sandbox/manifest.txt +++ b/res/dist/scripts/sandbox/manifest.txt @@ -1,3 +1,4 @@ background.lua +camera.lua light.lua player.lua diff --git a/src/ogre/CMakeLists.txt b/src/ogre/CMakeLists.txt index 2cd9b0fd3cc..28131557d71 100644 --- a/src/ogre/CMakeLists.txt +++ b/src/ogre/CMakeLists.txt @@ -1,4 +1,6 @@ add_sources( + ${CMAKE_CURRENT_SOURCE_DIR}/camera_system.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/camera_system.h ${CMAKE_CURRENT_SOURCE_DIR}/entity_system.cpp ${CMAKE_CURRENT_SOURCE_DIR}/entity_system.h ${CMAKE_CURRENT_SOURCE_DIR}/keyboard_system.cpp diff --git a/src/ogre/camera_system.cpp b/src/ogre/camera_system.cpp new file mode 100644 index 00000000000..c27da540204 --- /dev/null +++ b/src/ogre/camera_system.cpp @@ -0,0 +1,166 @@ +#include "ogre/camera_system.h" + +#include "engine/component_registry.h" +#include "engine/entity_filter.h" +#include "ogre/ogre_engine.h" +#include "ogre/scene_node_system.h" +#include "scripting/luabind.h" + +#include +#include +#include + +using namespace thrive; + +//////////////////////////////////////////////////////////////////////////////// +// OgreCameraComponent +//////////////////////////////////////////////////////////////////////////////// + +static void +OgreCameraComponent_touch( + OgreCameraComponent* self +) { + return self->m_properties.touch(); +} + + +static OgreCameraComponent::Properties& +OgreCameraComponent_getWorkingCopy( + OgreCameraComponent* self +) { + return self->m_properties.workingCopy(); +} + + +static const OgreCameraComponent::Properties& +OgreCameraComponent_getLatest( + OgreCameraComponent* self +) { + return self->m_properties.latest(); +} + + +luabind::scope +OgreCameraComponent::luaBindings() { + using namespace luabind; + return class_>("OgreCameraComponent") + .scope [ + def("TYPE_NAME", &OgreCameraComponent::TYPE_NAME), + def("TYPE_ID", &OgreCameraComponent::TYPE_ID), + class_("Properties") + .def_readwrite("polygonMode", &Properties::polygonMode) + .def_readwrite("fovY", &Properties::fovY) + .def_readwrite("nearClipDistance", &Properties::nearClipDistance) + .def_readwrite("farClipDistance", &Properties::farClipDistance) + .def_readwrite("aspectRatio", &Properties::aspectRatio) + ] + .enum_("PolygonMode") [ + value("PM_POINTS", Ogre::PM_POINTS), + value("PM_WIREFRAME", Ogre::PM_WIREFRAME), + value("PM_SOLID", Ogre::PM_SOLID) + ] + .def(constructor()) + .property("latest", OgreCameraComponent_getLatest) + .property("workingCopy", OgreCameraComponent_getWorkingCopy) + .def("touch", OgreCameraComponent_touch) + ; +} + +OgreCameraComponent::OgreCameraComponent( + std::string name +) : m_name(name) +{ +} + +REGISTER_COMPONENT(OgreCameraComponent) + + +//////////////////////////////////////////////////////////////////////////////// +// OgreCameraSystem +//////////////////////////////////////////////////////////////////////////////// + +struct OgreCameraSystem::Implementation { + + std::unordered_map m_cameras; + + Ogre::SceneManager* m_sceneManager = nullptr; + + EntityFilter< + OgreSceneNodeComponent, + OgreCameraComponent + > m_entities = {true}; +}; + + +OgreCameraSystem::OgreCameraSystem() + : m_impl(new Implementation()) +{ +} + + +OgreCameraSystem::~OgreCameraSystem() {} + + +void +OgreCameraSystem::init( + Engine* engine +) { + System::init(engine); + assert(m_impl->m_sceneManager == nullptr && "Double init of system"); + OgreEngine* ogreEngine = dynamic_cast(engine); + assert(ogreEngine != nullptr && "System requires an OgreEngine"); + m_impl->m_sceneManager = ogreEngine->sceneManager(); + m_impl->m_entities.setEngine(engine); +} + + +void +OgreCameraSystem::shutdown() { + m_impl->m_entities.setEngine(nullptr); + m_impl->m_sceneManager = nullptr; + System::shutdown(); +} + + +void +OgreCameraSystem::update(int) { + for (auto& value : m_impl->m_entities.addedEntities()) { + EntityId entityId = value.first; + OgreSceneNodeComponent* sceneNodeComponent = std::get<0>(value.second); + OgreCameraComponent* cameraComponent = std::get<1>(value.second); + Ogre::Camera* camera = m_impl->m_sceneManager->createCamera( + cameraComponent->m_name + ); + cameraComponent->m_camera = camera; + m_impl->m_cameras[entityId] = camera; + sceneNodeComponent->m_sceneNode->attachObject(camera); + // Test code for scriptable cameras + // TODO: Remove this when scriptable viewports are available (#24) + OgreEngine* ogreEngine = dynamic_cast(this->engine()); + ogreEngine->viewport()->setCamera(camera); + } + for (EntityId entityId : m_impl->m_entities.removedEntities()) { + Ogre::Camera* camera = m_impl->m_cameras[entityId]; + Ogre::SceneNode* sceneNode = camera->getParentSceneNode(); + sceneNode->detachObject(camera); + m_impl->m_sceneManager->destroyCamera(camera); + m_impl->m_cameras.erase(entityId); + } + m_impl->m_entities.clearChanges(); + for (auto& value : m_impl->m_entities) { + OgreCameraComponent* cameraComponent = std::get<1>(value.second); + if (cameraComponent->m_properties.hasChanges()) { + const auto& properties = cameraComponent->m_properties.stable(); + Ogre::Camera* camera = cameraComponent->m_camera; + // Update camera + camera->setPolygonMode(properties.polygonMode); + camera->setFOVy(properties.fovY); + camera->setNearClipDistance(properties.nearClipDistance); + camera->setFarClipDistance(properties.farClipDistance); + camera->setAspectRatio(properties.aspectRatio); + // Untouch + cameraComponent->m_properties.untouch(); + } + } +} + diff --git a/src/ogre/camera_system.h b/src/ogre/camera_system.h new file mode 100644 index 00000000000..18dc361dfa2 --- /dev/null +++ b/src/ogre/camera_system.h @@ -0,0 +1,140 @@ +#pragma once + +#include "engine/component.h" +#include "engine/shared_data.h" +#include "engine/system.h" + +#include +#include +#include + +namespace luabind { +class scope; +} + +namespace Ogre { +class Camera; +} + +namespace thrive { + +/** +* @brief A component for a camera +* +*/ +class OgreCameraComponent : public Component { + COMPONENT(OgreCamera) + +public: + + /** + * @brief Properties + */ + struct Properties { + /** + * @brief The level of rendering detail + */ + Ogre::PolygonMode polygonMode = Ogre::PM_SOLID; + + /** + * @brief The y-dimension field of view + */ + Ogre::Radian fovY = Ogre::Radian{45.0f}; + /** + * @brief Near clip distance + */ + Ogre::Real nearClipDistance = 100.0f; + /** + * @brief Far clip distance + */ + Ogre::Real farClipDistance = 10000.0f; + /** + * @brief Aspect ratio of the frustum viewport + */ + Ogre::Real aspectRatio = 1.3333f; + }; + + /** + * @brief Lua bindings + * + * Exposes the following \ref shared_data_lua shared properties: + * - \c Properties::polygonMode + * - \c Properties::fovY + * - \c Properties::nearClipDistance + * - \c Properties::farClipDistance + * - \c Properties::aspectRatio + * + * @return + */ + static luabind::scope + luaBindings(); + + /** + * @brief Constructor + * + * @param name + * The camera's name + */ + OgreCameraComponent( + std::string name + ); + + Ogre::Camera* m_camera = nullptr; + + /** + * @brief The camera's name + */ + const std::string m_name; + + /** + * @brief Shared properties + */ + RenderData + m_properties; + +}; + + +/** +* @brief Creates, updates and removes cameras +*/ +class OgreCameraSystem : public System { + +public: + + /** + * @brief Constructor + */ + OgreCameraSystem(); + + /** + * @brief Destructor + */ + ~OgreCameraSystem(); + + /** + * @brief Initializes the system + * + * @param engine + * Must be an OgreEngine + */ + void init(Engine* engine) override; + + /** + * @brief Shuts the system down + */ + void shutdown() override; + + /** + * @brief Updates the system + */ + void update(int) override; + +private: + + struct Implementation; + std::unique_ptr m_impl; +}; + +} + diff --git a/src/ogre/ogre_engine.cpp b/src/ogre/ogre_engine.cpp index b1916b13cad..5395a96762d 100644 --- a/src/ogre/ogre_engine.cpp +++ b/src/ogre/ogre_engine.cpp @@ -1,8 +1,9 @@ #include "ogre/ogre_engine.h" #include "game.h" -#include "ogre/keyboard_system.h" +#include "ogre/camera_system.h" #include "ogre/entity_system.h" +#include "ogre/keyboard_system.h" #include "ogre/light_system.h" #include "ogre/render_system.h" #include "ogre/scene_node_system.h" @@ -73,21 +74,6 @@ struct OgreEngine::Implementation : public Ogre::WindowEventListener { } } - void - setupCamera() { - m_camera = m_sceneManager->createCamera("PlayerCam"); - m_camera->setNearClipDistance(5); - m_camera->setFarClipDistance(10000); - m_camera->setAutoAspectRatio(true); - // Create node - m_cameraNode = m_sceneManager->getRootSceneNode()->createChildSceneNode( - "MainCameraNode", - Ogre::Vector3(0,0,30), - Ogre::Quaternion::IDENTITY - ); - m_cameraNode->attachObject(m_camera); - } - void setupInputManager() { const std::string HANDLE_NAME = "WINDOW"; @@ -119,9 +105,8 @@ struct OgreEngine::Implementation : public Ogre::WindowEventListener { void setupViewport() { - Ogre::Viewport* viewport = m_window->addViewport(m_camera); - viewport->setBackgroundColour(Ogre::ColourValue(0,0,0)); - m_camera->setAutoAspectRatio(true); + m_viewport = m_window->addViewport(nullptr); + m_viewport->setBackgroundColour(Ogre::ColourValue(0,0,0)); } void @@ -133,7 +118,8 @@ struct OgreEngine::Implementation : public Ogre::WindowEventListener { m_inputManager = nullptr; } - bool windowClosing( + bool + windowClosing( Ogre::RenderWindow* window ) override { if (window == m_window) { @@ -144,16 +130,14 @@ struct OgreEngine::Implementation : public Ogre::WindowEventListener { std::unique_ptr m_root; - Ogre::Camera* m_camera = nullptr; - - Ogre::SceneNode* m_cameraNode = nullptr; - OIS::InputManager* m_inputManager = nullptr; std::shared_ptr m_keyboardSystem = nullptr; Ogre::SceneManager* m_sceneManager = nullptr; + Ogre::Viewport* m_viewport = nullptr; + Ogre::RenderWindow* m_window = nullptr; }; @@ -189,7 +173,6 @@ OgreEngine::init( Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // Setup m_impl->setupSceneManager(); - m_impl->setupCamera(); m_impl->setupViewport(); m_impl->setupLighting(); m_impl->setupInputManager(); @@ -209,6 +192,11 @@ OgreEngine::init( 0, std::make_shared() ); + this->addSystem( + "cameras", + 0, + std::make_shared() + ); this->addSystem( "lights", 0, @@ -285,6 +273,12 @@ OgreEngine::update() { } +Ogre::Viewport* +OgreEngine::viewport() const { + return m_impl->m_viewport; +} + + Ogre::RenderWindow* OgreEngine::window() const { return m_impl->m_window; diff --git a/src/ogre/ogre_engine.h b/src/ogre/ogre_engine.h index 41b22a2c996..32291fe2008 100644 --- a/src/ogre/ogre_engine.h +++ b/src/ogre/ogre_engine.h @@ -8,6 +8,7 @@ namespace Ogre { class RenderWindow; class Root; class SceneManager; + class Viewport; } namespace OIS { @@ -88,6 +89,11 @@ class OgreEngine : public Engine { void update() override; + // Test code for scriptable cameras + // TODO: Remove this when scriptable viewports are available (#24) + Ogre::Viewport* + viewport() const; + /** * @brief The render window */ diff --git a/src/ogre/sky_system.cpp b/src/ogre/sky_system.cpp index d7713b43a95..84b50f7946a 100644 --- a/src/ogre/sky_system.cpp +++ b/src/ogre/sky_system.cpp @@ -77,7 +77,7 @@ struct SkySystem::Implementation { EntityFilter< Optional - > m_skyEntities; + > m_entities; }; @@ -99,13 +99,13 @@ SkySystem::init( OgreEngine* ogreEngine = dynamic_cast(engine); assert(ogreEngine != nullptr && "System requires an OgreEngine"); m_impl->m_sceneManager = ogreEngine->sceneManager(); - m_impl->m_skyEntities.setEngine(engine); + m_impl->m_entities.setEngine(engine); } void SkySystem::shutdown() { - m_impl->m_skyEntities.setEngine(nullptr); + m_impl->m_entities.setEngine(nullptr); m_impl->m_sceneManager->setSkyBoxEnabled(false); m_impl->m_sceneManager->setSkyDomeEnabled(false); m_impl->m_sceneManager->setSkyPlaneEnabled(false); @@ -116,7 +116,7 @@ SkySystem::shutdown() { void SkySystem::update(int) { - for (auto& value : m_impl->m_skyEntities) { + for (auto& value : m_impl->m_entities) { SkyPlaneComponent* plane = std::get<0>(value.second); if (plane and plane->m_properties.hasChanges()) { const SkyPlaneComponent::Properties& properties = plane->m_properties.stable(); diff --git a/src/ogre/sky_system.h b/src/ogre/sky_system.h index b7481fba1a5..cf59944e5e8 100644 --- a/src/ogre/sky_system.h +++ b/src/ogre/sky_system.h @@ -8,9 +8,6 @@ #include #include - -#include - namespace luabind { class scope; } diff --git a/src/scripting/script_initializer.cpp b/src/scripting/script_initializer.cpp index 53cb08bb4d0..10a9e0945c0 100644 --- a/src/scripting/script_initializer.cpp +++ b/src/scripting/script_initializer.cpp @@ -4,9 +4,10 @@ #include "common/transform.h" #include "engine/component.h" #include "engine/entity.h" -#include "ogre/on_key.h" +#include "ogre/camera_system.h" #include "ogre/entity_system.h" #include "ogre/light_system.h" +#include "ogre/on_key.h" #include "ogre/scene_node_system.h" #include "ogre/script_bindings.h" #include "ogre/sky_system.h" @@ -41,8 +42,9 @@ thrive::initializeLua( // Rendering Components OgreBindings::luaBindings(), OnKeyComponent::luaBindings(), - OgreLightComponent::luaBindings(), + OgreCameraComponent::luaBindings(), OgreEntityComponent::luaBindings(), + OgreLightComponent::luaBindings(), OgreSceneNodeComponent::luaBindings(), SkyPlaneComponent::luaBindings() ];