diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 3d3e0d8..eab2543 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -57,7 +57,7 @@ jobs: run: | sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" sudo apt-get update -y -qq - sudo apt-get install libsdl2-dev libglm-dev libvulkan-volk-dev nlohmann-json3-dev libvulkan-dev libstb-dev + sudo apt-get install libsdl2-dev libglm-dev libvulkan-volk-dev nlohmann-json3-dev libvulkan-dev libstb-dev glslc doxygen - name: Set reusable strings diff --git a/.gitignore b/.gitignore index 4a4570c..1768168 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ CMakeFiles/ Makefile cmake_install.cmake install_manifest.txt -*.dir/ # vcpkg vcpkg/ @@ -50,7 +49,6 @@ vcpkg-installed/ *.log *.swp *.swo -*~ # OS-specific files .DS_Store diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index b5525fe..ef27c10 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -28,6 +28,16 @@ # Find Python interpreter find_package(Python3 COMPONENTS Interpreter REQUIRED) +if(CMAKE_BUILD_TYPE) + set(BUILD_CONFIG "${CMAKE_BUILD_TYPE}") +elseif(CMAKE_CONFIGURATION_TYPES) + # For multi-config generators, use the current config from the --config flag + # This requires CMake 3.15+ for proper generator expressions + set(BUILD_CONFIG "$") +else() + set(BUILD_CONFIG "Release") +endif() + # Get the build configuration (Debug/Release) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(BUILD_CONFIG "Debug") diff --git a/src/contrib/vcpkg b/src/contrib/vcpkg index e7d7451..f75c836 160000 --- a/src/contrib/vcpkg +++ b/src/contrib/vcpkg @@ -1 +1 @@ -Subproject commit e7d7451462697d77ef319ddf2da8ff7320a82662 +Subproject commit f75c836a67777a86a2c1116a28b179827f028b66 diff --git a/src/editor/CMakeLists.txt b/src/editor/CMakeLists.txt index 016348a..20d668a 100644 --- a/src/editor/CMakeLists.txt +++ b/src/editor/CMakeLists.txt @@ -8,3 +8,5 @@ target_link_libraries(segfault_editor SDL2::SDL2 glm::glm ) + +add_dependencies(segfault_editor compile_all_assets) diff --git a/src/examples/behaviortree_sample/CMakeLists.txt b/src/examples/behaviortree_sample/CMakeLists.txt index 630db8e..e8364f9 100644 --- a/src/examples/behaviortree_sample/CMakeLists.txt +++ b/src/examples/behaviortree_sample/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(behaviortree_sample behaviortree_sample.cpp) target_link_libraries(behaviortree_sample example_common) +add_dependencies(behaviortree_sample compile_all_assets) set_target_properties(behaviortree_sample PROPERTIES FOLDER examples ) diff --git a/src/examples/hello_world/CMakeLists.txt b/src/examples/hello_world/CMakeLists.txt index 6ec6896..a4aa294 100644 --- a/src/examples/hello_world/CMakeLists.txt +++ b/src/examples/hello_world/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(hello_world hello_world.cpp) target_link_libraries(hello_world example_common) +add_dependencies(hello_world compile_all_assets) set_target_properties(hello_world PROPERTIES FOLDER examples ) diff --git a/src/examples/scene_sample/CMakeLists.txt b/src/examples/scene_sample/CMakeLists.txt index 50a4b16..238d408 100644 --- a/src/examples/scene_sample/CMakeLists.txt +++ b/src/examples/scene_sample/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(scene_sample scene_sample.cpp) target_link_libraries(scene_sample example_common) +add_dependencies(scene_sample compile_all_assets) set_target_properties(scene_sample PROPERTIES FOLDER examples ) diff --git a/src/examples/scene_sample_2d/CMakeLists.txt b/src/examples/scene_sample_2d/CMakeLists.txt index 5a31cae..0fc904d 100644 --- a/src/examples/scene_sample_2d/CMakeLists.txt +++ b/src/examples/scene_sample_2d/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(scene_sample_2d scene_sample_2d.cpp) target_link_libraries(scene_sample_2d example_common) +add_dependencies(scene_sample_2d compile_all_assets) set_target_properties(scene_sample_2d PROPERTIES FOLDER examples ) diff --git a/src/runtime/CMakeLists.txt b/src/runtime/CMakeLists.txt index d68a747..2ac88bd 100644 --- a/src/runtime/CMakeLists.txt +++ b/src/runtime/CMakeLists.txt @@ -13,6 +13,11 @@ SET(segfault_core_src set (segfault_scene_src scene/camera.h + scene/scene.h + scene/scene2d.h + scene/scene2d.cpp + scene/scene2dmanager.h + scene/scene2dmanager.cpp ) SET(segfault_renderer_src @@ -50,6 +55,7 @@ source_group(ai FILES ${segfault_ai_src} ) source_group(core FILES ${segfault_core_src} ) source_group(application FILES ${segfault_application_src} ) source_group(renderer FILES ${segfault_renderer_src} ) +source_group(scene FILES ${segfault_scene_src} ) ADD_LIBRARY(segfault_runtime SHARED ${segfault_ai_src} diff --git a/src/runtime/scene/scene2d.cpp b/src/runtime/scene/scene2d.cpp new file mode 100644 index 0000000..7838dbe --- /dev/null +++ b/src/runtime/scene/scene2d.cpp @@ -0,0 +1,788 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015-2026 Segfault by Kim Kulling + +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 "scene/scene2d.h" +#include "renderer/RHI.h" + +#include + +namespace segfault::scene { + + //--------------------------------------------------------------------------------------------- + // Camera2D implementation + //--------------------------------------------------------------------------------------------- + + Camera2D::Camera2D() : mZoom(1.0f), mRotation(0.0f), mViewMatrix(1.0f), mProjectionMatrix(1.0f), mDirty(true) { + updateMatrices(); + } + + void Camera2D::setOrthographic(float left, float right, float bottom, float top, float near, float far) { + mProjectionMatrix = glm::ortho(left, right, bottom, top, near, far); + mDirty = true; + } + + void Camera2D::setOrthographicFromViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height, float near, float far) { + float halfWidth = static_cast(width) * 0.5f; + float halfHeight = static_cast(height) * 0.5f; + setOrthographic(-halfWidth, halfWidth, -halfHeight, halfHeight, near, far); + mViewport.x = x; + mViewport.y = y; + mViewport.width = width; + mViewport.height = height; + mDirty = true; + } + + void Camera2D::setPosition(const glm::vec2& position) { + if (mPosition != position) { + mPosition = position; + mDirty = true; + } + } + + void Camera2D::setPosition(float x, float y) { + setPosition(glm::vec2(x, y)); + } + + const glm::vec2& Camera2D::getPosition() const { + return mPosition; + } + + void Camera2D::setZoom(float zoom) { + if (mZoom != zoom) { + mZoom = std::max(0.001f, zoom); // Prevent zero or negative zoom + mDirty = true; + } + } + + float Camera2D::getZoom() const { + return mZoom; + } + + void Camera2D::setRotation(float angle) { + if (mRotation != angle) { + mRotation = angle; + mDirty = true; + } + } + + float Camera2D::getRotation() const { + return mRotation; + } + + const glm::mat4& Camera2D::getViewMatrix() const { + if (mDirty) { + const_cast(this)->updateMatrices(); + } + return mViewMatrix; + } + + const glm::mat4& Camera2D::getProjectionMatrix() const { + return mProjectionMatrix; + } + + glm::mat4 Camera2D::getViewProjectionMatrix() const { + if (mDirty) { + const_cast(this)->updateMatrices(); + } + return mProjectionMatrix * mViewMatrix; + } + + glm::vec2 Camera2D::screenToWorld(const glm::vec2& screenPos, uint32_t viewportWidth, uint32_t viewportHeight) const { + // Convert screen coordinates to normalized device coordinates + float ndcX = (2.0f * screenPos.x) / static_cast(viewportWidth) - 1.0f; + float ndcY = 1.0f - (2.0f * screenPos.y) / static_cast(viewportHeight); + + // Create NDC position with z=0 + glm::vec4 ndcPos(ndcX, ndcY, 0.0f, 1.0f); + + // Apply inverse view-projection matrix + glm::mat4 invVP = glm::inverse(getViewProjectionMatrix()); + glm::vec4 worldPos = invVP * ndcPos; + + return glm::vec2(worldPos.x, worldPos.y); + } + + glm::vec2 Camera2D::worldToScreen(const glm::vec2& worldPos, uint32_t viewportWidth, uint32_t viewportHeight) const { + // Apply view-projection matrix + glm::vec4 clipPos = getViewProjectionMatrix() * glm::vec4(worldPos.x, worldPos.y, 0.0f, 1.0f); + + // Convert from clip space to screen space + float screenX = ((clipPos.x / clipPos.w) + 1.0f) * 0.5f * static_cast(viewportWidth); + float screenY = (1.0f - (clipPos.y / clipPos.w)) * 0.5f * static_cast(viewportHeight); + + return glm::vec2(screenX, screenY); + } + + void Camera2D::move(const glm::vec2& offset) { + mPosition += offset; + mDirty = true; + } + + void Camera2D::resize(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { + setOrthographicFromViewport(x, y, width, height); + } + + void Camera2D::setViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { + mViewport.x = x; + mViewport.y = y; + mViewport.width = width; + mViewport.height = height; + resize(x, y, width, height); + } + + const core::Rect& Camera2D::getViewport() const { + return mViewport; + } + + void Camera2D::updateMatrices() { + if (!mDirty) return; + + // Build view matrix: translate by position, rotate, scale by zoom + glm::mat4 transform = glm::mat4(1.0f); + + // Apply zoom (scale) + transform = glm::scale(transform, glm::vec3(mZoom, mZoom, 1.0f)); + + // Apply rotation + if (mRotation != 0.0f) { + transform = glm::rotate(transform, glm::radians(mRotation), glm::vec3(0.0f, 0.0f, 1.0f)); + } + + // Apply translation + transform = glm::translate(transform, glm::vec3(-mPosition.x, -mPosition.y, 0.0f)); + + mViewMatrix = transform; + mDirty = false; + } + + //--------------------------------------------------------------------------------------------- + // Layer2D implementation + //--------------------------------------------------------------------------------------------- + + Layer2D::Layer2D() : mVisible(true), mRenderOrder(0), mCamera(nullptr), mUseOwnCamera(false) { + // empty + } + + bool Layer2D::init(renderer::RHI& rhi) { + // Base layer initialization + return true; + } + + void Layer2D::shutdown() { + // Base layer shutdown + } + + void Layer2D::update(float deltaTime) { + // Base layer update + } + + void Layer2D::render(renderer::RHI& rhi) { + // Base layer render + } + + void Layer2D::setName(const std::string& name) { + mName = name; + } + + const std::string& Layer2D::getName() const { + return mName; + } + + void Layer2D::setVisible(bool visible) { + mVisible = visible; + } + + bool Layer2D::isVisible() const { + return mVisible; + } + + void Layer2D::setRenderOrder(int32_t order) { + mRenderOrder = order; + } + + int32_t Layer2D::getRenderOrder() const { + return mRenderOrder; + } + + void Layer2D::setCamera(Camera2D* camera) { + mCamera = camera; + } + + Camera2D* Layer2D::getCamera() const { + return mCamera; + } + + void Layer2D::setUseOwnCamera(bool useOwnCamera) { + mUseOwnCamera = useOwnCamera; + } + + bool Layer2D::getUseOwnCamera() const { + return mUseOwnCamera; + } + + //--------------------------------------------------------------------------------------------- + // Entity2D implementation + //--------------------------------------------------------------------------------------------- + + bool Entity2D::isValid() const { + return id != 0; + } + + bool Entity2D::operator==(const Entity2D& other) const { + return id == other.id; + } + + bool Entity2D::operator!=(const Entity2D& other) const { + return id != other.id; + } + + //--------------------------------------------------------------------------------------------- + // Transform2DComponent implementation + //--------------------------------------------------------------------------------------------- + + void Transform2DComponent::updateWorldMatrix() { + if (!mDirty) { + return; + } + + auto transform = glm::mat4(1.0f); + + // Translate to position + transform = glm::translate(transform, glm::vec3(mPosition.x, mPosition.y, 0.0f)); + + // Rotate around origin + if (mRotation != 0.0f) { + transform = glm::translate(transform, glm::vec3(mSize.x * mOrigin.x, mSize.y * mOrigin.y, 0.0f)); + transform = glm::rotate(transform, glm::radians(mRotation), glm::vec3(0.0f, 0.0f, 1.0f)); + transform = glm::translate(transform, glm::vec3(-mSize.x * mOrigin.x, -mSize.y * mOrigin.y, 0.0f)); + } + + // Scale + transform = glm::scale(transform, glm::vec3(mScale.x, mScale.y, 1.0f)); + + mWorldMatrix = transform; + mDirty = false; + } + + void Transform2DComponent::setPosition(const glm::vec2& position) { + if (mPosition != position) { + mPosition = position; + mDirty = true; + } + } + + void Transform2DComponent::setRotation(float rotation) { + if (mRotation != rotation) { + mRotation = rotation; + mDirty = true; + } + } + + void Transform2DComponent::setScale(const glm::vec2& scale) { + if (mScale != scale) { + mScale = scale; + mDirty = true; + } + } + + void Transform2DComponent::setSize(const glm::vec2& size) { + if (mSize != size) { + mSize = size; + mDirty = true; + } + } + + void Transform2DComponent::setOrigin(const glm::vec2& origin) { + if (mOrigin != origin) { + mOrigin = origin; + mDirty = true; + } + } + + //--------------------------------------------------------------------------------------------- + // SpriteComponent implementation + //--------------------------------------------------------------------------------------------- + + SpriteComponent::SpriteComponent(core::guid textureHandle) : mTextureHandle(textureHandle) { + // empty + } + + void SpriteComponent::setTexture(core::guid textureHandle) { + mTextureHandle = textureHandle; + } + + void SpriteComponent::setColor(const glm::vec4& color) { + mColor = color; + } + + void SpriteComponent::setAlpha(float alpha) { + mAlpha = glm::clamp(alpha, 0.0f, 1.0f); + } + + void SpriteComponent::setTextureRect(const core::Rect& rect) { + mTextureRect = rect; + } + + void SpriteComponent::setFlip(bool flipX, bool flipY) { + mFlipX = flipX; + mFlipY = flipY; + } + + void SpriteComponent::setVisible(bool visible) { + mVisible = visible; + } + + //--------------------------------------------------------------------------------------------- + // TextComponent implementation + //--------------------------------------------------------------------------------------------- + + TextComponent::TextComponent(const std::string& text, core::guid fontHandle) + : mText(text), mFontHandle(fontHandle), mDirty(true) { + // empty + } + + void TextComponent::setText(const std::string& text) { + if (mText != text) { + mText = text; + mDirty = true; + } + } + + void TextComponent::setFont(core::guid fontHandle) { + if (mFontHandle != fontHandle) { + mFontHandle = fontHandle; + mDirty = true; + } + } + + void TextComponent::setColor(const glm::vec4& color) { + mColor = color; + } + + void TextComponent::setFontSize(float fontSize) { + if (mFontSize != fontSize) { + mFontSize = fontSize; + mDirty = true; + } + } + + void TextComponent::setHorizontalAlignment(TextAlignment alignment) { + mHorizontalAlignment = alignment; + mDirty = true; + } + + void TextComponent::setVerticalAlignment(VerticalAlignment alignment) { + mVerticalAlignment = alignment; + mDirty = true; + } + + void TextComponent::setVisible(bool visible) { + mVisible = visible; + } + + //--------------------------------------------------------------------------------------------- + // Render2DComponent implementation + //--------------------------------------------------------------------------------------------- + + void Render2DComponent::setLayer(Layer2D* layer) { + mLayer = layer; + } + + void Render2DComponent::setRenderOrder(int32_t order) { + mRenderOrder = order; + } + + void Render2DComponent::setVisible(bool visible) { + mVisible = visible; + } + + //--------------------------------------------------------------------------------------------- + // Animation2DComponent implementation + //--------------------------------------------------------------------------------------------- + + void Animation2DComponent::addFrame(const core::Rect& textureRect, float duration) { + mFrames.push_back({ textureRect, duration }); + mDirty = true; + } + + void Animation2DComponent::setFrames(const std::vector& frames) { + mFrames = frames; + mDirty = true; + } + + void Animation2DComponent::play(bool loop) { + mPlaying = true; + mLoop = loop; + } + + void Animation2DComponent::stop() { + mPlaying = false; + mCurrentFrame = 0; + mFrameTimer = 0.0f; + } + + void Animation2DComponent::pause() { + mPlaying = false; + } + + void Animation2DComponent::resume() { + mPlaying = true; + } + + void Animation2DComponent::update(float deltaTime) { + if (!mPlaying || mFrames.empty()) return; + + mFrameTimer += deltaTime * mAnimationSpeed; + + const Frame& currentFrame = mFrames[mCurrentFrame]; + + if (mCurrentFrame >= mFrames.size()) { + mCurrentFrame = 0; + } + + while (mFrames[mCurrentFrame].mDuration > 0.0f && mFrameTimer >= mFrames[mCurrentFrame].mDuration) { + mFrameTimer -= mFrames[mCurrentFrame].mDuration; + mCurrentFrame++; + + if (mCurrentFrame >= mFrames.size()) { + if (mLoop) { + mCurrentFrame = 0; + } else { + mPlaying = false; + mCurrentFrame = mFrames.size() - 1; + break; + } + } + } + + mDirty = true; + } + + core::Rect Animation2DComponent::getCurrentFrameRect() const { + if (mFrames.empty()) return core::Rect(); + return mFrames[mCurrentFrame].mTextureRect; + } + + uint32_t Animation2DComponent::getCurrentFrameIndex() const { + return mCurrentFrame; + } + + void Animation2DComponent::setCurrentFrameIndex(uint32_t frameIndex) { + if (frameIndex < mFrames.size()) { + mCurrentFrame = frameIndex; + mFrameTimer = 0.0f; + mDirty = true; + } + } + + void Animation2DComponent::setAnimationSpeed(float speed) { + mAnimationSpeed = std::max(0.0f, speed); + } + + bool Animation2DComponent::isPlaying() const { + return mPlaying; + } + + bool Animation2DComponent::isLooping() const { + return mLoop; + } + + uint32_t Animation2DComponent::getFrameCount() const { + return static_cast(mFrames.size()); + } + + //--------------------------------------------------------------------------------------------- + // Scene2D implementation + //--------------------------------------------------------------------------------------------- + + Scene2D::Scene2D() : mViewportWidth(0), mViewportHeight(0), mManager(nullptr) { + mName = "UnnamedScene"; + mDefaultLayer = std::make_unique(); + mDefaultLayer->setName("Default"); + mDefaultLayer->init(*static_cast(nullptr)); // Will be properly initialized later + } + + Scene2D::~Scene2D() { + shutdown(); + } + + bool Scene2D::init(renderer::RHI& rhi) { + // Initialize main camera + mMainCamera.resize(0, 0, mViewportWidth, mViewportHeight); + + // Initialize default layer + if (mDefaultLayer) { + mDefaultLayer->init(rhi); + } + + // Initialize all other layers + for (auto& pair : mLayers) { + pair.second->init(rhi); + } + + onLoad(); + return true; + } + + void Scene2D::shutdown() { + onUnload(); + + // Shutdown all layers + for (auto& pair : mLayers) { + pair.second->shutdown(); + } + mLayers.clear(); + + if (mDefaultLayer) { + mDefaultLayer->shutdown(); + } + } + + void Scene2D::update(float deltaTime) { + // Update all components that need updating + for (auto& component : mAnimationPool.data()) { + if (component.isPlaying()) { + component.update(deltaTime); + } + } + + // Update all layers + for (auto& pair : mLayers) { + if (pair.second->isVisible()) { + pair.second->update(deltaTime); + } + } + } + + void Scene2D::render(renderer::RHI& rhi) { + // Update transform matrices for all entities + for (auto& component : mTransformPool.data()) { + if (component.mDirty) { + component.updateWorldMatrix(); + } + } + + // Render all layers in order + std::vector renderOrder; + + // Collect all layers + for (auto& pair : mLayers) { + renderOrder.push_back(pair.second.get()); + } + + // Sort by render order + std::sort(renderOrder.begin(), renderOrder.end(), [](Layer2D* a, Layer2D* b) { + return a->getRenderOrder() < b->getRenderOrder(); + }); + + // Render default layer first + if (mDefaultLayer && mDefaultLayer->isVisible()) { + mDefaultLayer->render(rhi); + } + + // Render sorted layers + for (Layer2D* layer : renderOrder) { + if (layer->isVisible()) { + layer->render(rhi); + } + } + } + + void Scene2D::onActivate() { + // Override in derived classes + } + + void Scene2D::onDeactivate() { + // Override in derived classes + } + + void Scene2D::onLoad() { + // Override in derived classes + } + + void Scene2D::onUnload() { + // Override in derived classes + } + + Entity2D Scene2D::createEntity() { + Entity2D entity; + entity.id = mNextEntityId++; + return entity; + } + + void Scene2D::destroyEntity(Entity2D entity) { + if (!isValid(entity)) return; + + mTransformPool.remove(entity); + mSpritePool.remove(entity); + mTextPool.remove(entity); + mRenderPool.remove(entity); + mAnimationPool.remove(entity); + } + + Transform2DComponent& Scene2D::addTransformComponent(Entity2D entity) { + return mTransformPool.add(entity); + } + + SpriteComponent& Scene2D::addSpriteComponent(Entity2D entity) { + return mSpritePool.add(entity); + } + + TextComponent& Scene2D::addTextComponent(Entity2D entity) { + return mTextPool.add(entity); + } + + Render2DComponent& Scene2D::addRenderComponent(Entity2D entity) { + Render2DComponent& component = mRenderPool.add(entity); + component.setLayer(mDefaultLayer.get()); + return component; + } + + Animation2DComponent& Scene2D::addAnimationComponent(Entity2D entity) { + return mAnimationPool.add(entity); + } + + Transform2DComponent* Scene2D::getTransformComponent(Entity2D entity) { + return mTransformPool.get(entity); + } + + SpriteComponent* Scene2D::getSpriteComponent(Entity2D entity) { + return mSpritePool.get(entity); + } + + TextComponent* Scene2D::getTextComponent(Entity2D entity) { + return mTextPool.get(entity); + } + + Render2DComponent* Scene2D::getRenderComponent(Entity2D entity) { + return mRenderPool.get(entity); + } + + Animation2DComponent* Scene2D::getAnimationComponent(Entity2D entity) { + return mAnimationPool.get(entity); + } + + Layer2D* Scene2D::createLayer(const std::string& name) { + if (mLayers.find(name) != mLayers.end()) { + return nullptr; // Layer already exists + } + + auto layer = std::make_unique(); + layer->setName(name); + Layer2D* result = layer.get(); + mLayers[name] = std::move(layer); + return result; + } + + bool Scene2D::destroyLayer(const std::string& name) { + auto it = mLayers.find(name); + if (it != mLayers.end()) { + it->second->shutdown(); + mLayers.erase(it); + return true; + } + return false; + } + + Layer2D* Scene2D::getLayer(const std::string& name) const { + auto it = mLayers.find(name); + if (it != mLayers.end()) { + return it->second.get(); + } + return nullptr; + } + + Layer2D* Scene2D::getDefaultLayer() const { + return mDefaultLayer.get(); + } + + Camera2D& Scene2D::getMainCamera() { + return mMainCamera; + } + + const Camera2D& Scene2D::getMainCamera() const { + return mMainCamera; + } + + void Scene2D::setViewportSize(uint32_t width, uint32_t height) { + mViewportWidth = width; + mViewportHeight = height; + mMainCamera.resize(0, 0, width, height); + } + + uint32_t Scene2D::getViewportWidth() const { + return mViewportWidth; + } + + uint32_t Scene2D::getViewportHeight() const { + return mViewportHeight; + } + + bool Scene2D::isValid(Entity2D entity) const { + return entity.id != 0; + } + + const std::string& Scene2D::getName() const { + return mName; + } + + void Scene2D::setName(const std::string& name) { + mName = name; + } + + Scene2DManager* Scene2D::getManager() const { + return mManager; + } + + //--------------------------------------------------------------------------------------------- + // SimpleScene2D implementation + //--------------------------------------------------------------------------------------------- + + SimpleScene2D::SimpleScene2D() { + // empty + } + + bool SimpleScene2D::init(renderer::RHI& rhi) { + if (!Scene2D::init(rhi)) { + return false; + } + return true; + } + + Entity2D SimpleScene2D::createSprite(core::guid textureHandle, const glm::vec2& position, const glm::vec2& size) { + Entity2D entity = createEntity(); + + Transform2DComponent& transform = addTransformComponent(entity); + transform.setPosition(position); + transform.setSize(size); + + SpriteComponent& sprite = addSpriteComponent(entity); + sprite.setTexture(textureHandle); + + Render2DComponent& render = addRenderComponent(entity); + render.setVisible(true); + + return entity; + } + +} // namespace segfault::scene diff --git a/src/runtime/scene/scene2d.h b/src/runtime/scene/scene2d.h new file mode 100644 index 0000000..2b01676 --- /dev/null +++ b/src/runtime/scene/scene2d.h @@ -0,0 +1,878 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015-2026 Segfault by Kim Kulling + +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 "core/segfault.h" +#include "core/ifilemanager.h" +#include "renderer/RHI.h" + +#include +#include +#include +#include + +#include +#include +#include + +namespace segfault::scene { + + // Forward declarations + class Scene2DManager; + class Layer2D; + + //--------------------------------------------------------------------------------------------- + /// @brief 2D Camera specifically designed for orthographic projection. + /// + /// Supports zooming, panning, and viewport operations for 2D rendering. + //--------------------------------------------------------------------------------------------- + class SEGFAULT_EXPORT Camera2D final { + public: + /// @brief Constructs a new Camera2D with default orthographic projection. + Camera2D(); + + /// @brief Destroys the Camera2D. + ~Camera2D() = default; + + //----------------------------------------------------------------------------------------- + /// @brief Sets up an orthographic projection. + /// @param[ in ] left The left coordinate of the viewport. + /// @param[ in ] right The right coordinate of the viewport. + /// @param[ in ] bottom The bottom coordinate of the viewport. + /// @param[ in ] top The top coordinate of the viewport. + /// @param[ in ] near The near clipping plane. + /// @param[ in ] far The far clipping plane. + //----------------------------------------------------------------------------------------- + void setOrthographic( float left, float right, float bottom, float top, float near = -1.0f, float far = 1.0f); + + //----------------------------------------------------------------------------------------- + /// @brief Sets up an orthographic projection based on viewport size. + /// @param[ in ] width The width of the viewport. + /// @param[ in ] height The height of the viewport. + /// @param[ in ] near The near clipping plane. + /// @param[ in ] far The far clipping plane. + //----------------------------------------------------------------------------------------- + void setOrthographicFromViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height, float near = -1.0f, float far = 1.0f); + + //----------------------------------------------------------------------------------------- + /// @brief Sets the position of the camera. + /// @param[ in ] position The 2D position of the camera. + //----------------------------------------------------------------------------------------- + void setPosition(const glm::vec2& position); + + //----------------------------------------------------------------------------------------- + /// @brief Sets the position of the camera. + /// @param[ in ] x The x-coordinate of the camera position. + /// @param[ in ] y The y-coordinate of the camera position. + //----------------------------------------------------------------------------------------- + void setPosition(float x, float y); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the position of the camera. + /// @return The 2D position of the camera. + //----------------------------------------------------------------------------------------- + const glm::vec2& getPosition() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the zoom level of the camera. + /// @param[ in ] zoom The zoom level (1.0 = normal, >1.0 = zoomed in, <1.0 = zoomed out). + //----------------------------------------------------------------------------------------- + void setZoom(float zoom); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the zoom level of the camera. + /// @return The current zoom level. + //----------------------------------------------------------------------------------------- + float getZoom() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the rotation of the camera in degrees. + /// @param[ in ] angle The rotation angle in degrees. + //----------------------------------------------------------------------------------------- + void setRotation(float angle); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the rotation of the camera in degrees. + /// @return The current rotation angle in degrees. + //----------------------------------------------------------------------------------------- + float getRotation() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the view matrix. + /// @return The view matrix. + //----------------------------------------------------------------------------------------- + const glm::mat4& getViewMatrix() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the projection matrix. + /// @return The projection matrix. + //----------------------------------------------------------------------------------------- + const glm::mat4& getProjectionMatrix() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the combined view-projection matrix. + /// @return The view-projection matrix. + //----------------------------------------------------------------------------------------- + glm::mat4 getViewProjectionMatrix() const; + + //----------------------------------------------------------------------------------------- + /// @brief Converts screen coordinates to world coordinates. + /// @param[ in ] screenPos The screen position (in pixels). + /// @param[ in ] viewportWidth The width of the viewport in pixels. + /// @param[ in ] viewportHeight The height of the viewport in pixels. + /// @return The corresponding world position. + //----------------------------------------------------------------------------------------- + glm::vec2 screenToWorld(const glm::vec2& screenPos, uint32_t viewportWidth, uint32_t viewportHeight) const; + + //----------------------------------------------------------------------------------------- + /// @brief Converts world coordinates to screen coordinates. + /// @param[ in ] worldPos The world position. + /// @param[ in ] viewportWidth The width of the viewport in pixels. + /// @param[ in ] viewportHeight The height of the viewport in pixels. + /// @return The corresponding screen position (in pixels). + //----------------------------------------------------------------------------------------- + glm::vec2 worldToScreen(const glm::vec2& worldPos, uint32_t viewportWidth, uint32_t viewportHeight) const; + + //----------------------------------------------------------------------------------------- + /// @brief Moves the camera by the specified offset. + /// @param[ in ] offset The offset to move the camera by. + //----------------------------------------------------------------------------------------- + void move(const glm::vec2& offset); + + //----------------------------------------------------------------------------------------- + /// @brief Resizes the camera viewport. + /// @param[ in ] x The x-coordinate of the viewport. + /// @param[ in ] y The y-coordinate of the viewport. + /// @param[ in ] width The new width of the viewport. + /// @param[ in ] height The new height of the viewport. + //----------------------------------------------------------------------------------------- + void resize(uint32_t x, uint32_t y, uint32_t width, uint32_t height); + + //----------------------------------------------------------------------------------------- + /// @brief Sets the viewport boundaries. + /// @param[ in ] x The x-coordinate of the viewport. + /// @param[ in ] y The y-coordinate of the viewport. + /// @param[ in ] width The width of the viewport. + /// @param[ in ] height The height of the viewport. + //----------------------------------------------------------------------------------------- + void setViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the viewport rectangle. + /// @return The viewport rectangle. + //----------------------------------------------------------------------------------------- + const core::Rect& getViewport() const; + + private: + glm::vec2 mPosition{ 0.0f, 0.0f }; + float mZoom{ 1.0f }; + float mRotation{ 0.0f }; + glm::mat4 mViewMatrix{ 1.0f }; + glm::mat4 mProjectionMatrix{ 1.0f }; + core::Rect mViewport{ 0, 0, 0, 0 }; + + bool mDirty{ true }; + + void updateMatrices(); + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Base class for all 2D layers. + /// + /// Layers are used to organize 2D rendering into separate groups with their own + /// rendering order, camera, and visibility settings. + //--------------------------------------------------------------------------------------------- + class SEGFAULT_EXPORT Layer2D { + public: + /// @brief Constructs a new Layer2D. + Layer2D(); + + /// @brief Destroys the Layer2D. + virtual ~Layer2D() = default; + + /// @brief Initializes the layer. + /// @param[ in ] rhi The rendering hardware interface. + /// @return True if initialization was successful, false otherwise. + virtual bool init(renderer::RHI& rhi); + + /// @brief Shuts down the layer and releases resources. + virtual void shutdown(); + + /// @brief Updates the layer. + /// @param[ in ] deltaTime The time elapsed since the last frame. + virtual void update(float deltaTime); + + /// @brief Renders the layer. + /// @param[ in ] rhi The rendering hardware interface. + virtual void render(renderer::RHI& rhi); + + //----------------------------------------------------------------------------------------- + /// @brief Sets the name of the layer. + /// @param[ in ] name The name of the layer. + //----------------------------------------------------------------------------------------- + void setName(const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the name of the layer. + /// @return The name of the layer. + //----------------------------------------------------------------------------------------- + const std::string& getName() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the visibility of the layer. + /// @param[ in ] visible True to make the layer visible, false to hide it. + //----------------------------------------------------------------------------------------- + void setVisible(bool visible); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the visibility of the layer. + /// @return True if the layer is visible, false otherwise. + //----------------------------------------------------------------------------------------- + bool isVisible() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the rendering order of the layer (lower values render first). + /// @param[ in ] order The rendering order. + //----------------------------------------------------------------------------------------- + void setRenderOrder(int32_t order); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the rendering order of the layer. + /// @return The rendering order. + //----------------------------------------------------------------------------------------- + int32_t getRenderOrder() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the camera for this layer. + /// @param[ in ] camera The camera to use for rendering this layer. + //----------------------------------------------------------------------------------------- + void setCamera(Camera2D* camera); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the camera for this layer. + /// @return Pointer to the camera, or nullptr if using the default camera. + //----------------------------------------------------------------------------------------- + Camera2D* getCamera() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets whether this layer uses its own camera or the scene's default camera. + /// @param[ in ] useOwnCamera True to use the layer's own camera, false to use the scene's camera. + //----------------------------------------------------------------------------------------- + void setUseOwnCamera(bool useOwnCamera); + + //----------------------------------------------------------------------------------------- + /// @brief Gets whether this layer uses its own camera. + /// @return True if using own camera, false otherwise. + //----------------------------------------------------------------------------------------- + bool getUseOwnCamera() const; + + protected: + std::string mName; + bool mVisible{ true }; + int32_t mRenderOrder{ 0 }; + Camera2D* mCamera{ nullptr }; + bool mUseOwnCamera{ false }; + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Entity handle for 2D scene objects. + //--------------------------------------------------------------------------------------------- + struct SEGFAULT_EXPORT Entity2D { + core::guid id{ 0 }; + + /// @brief Checks if the entity is valid. + /// @return True if the entity is valid, false otherwise. + bool isValid() const; + + /// @brief Comparison operator. + /// @param[ in ] other The other entity to compare with. + /// @return True if the entities are equal, false otherwise. + bool operator == (const Entity2D& other) const; + + /// @brief Comparison operator. + /// @param[ in ] other The other entity to compare with. + /// @return True if the entities are not equal, false otherwise. + bool operator != (const Entity2D& other) const; + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Transform component for 2D entities. + /// + /// Stores position, rotation, scale, and other transform properties for 2D rendering. + //--------------------------------------------------------------------------------------------- + struct SEGFAULT_EXPORT Transform2DComponent final { + glm::vec2 mPosition{ 0.0f, 0.0f }; + float mRotation{ 0.0f }; // in degrees + glm::vec2 mScale{ 1.0f, 1.0f }; + glm::vec2 mOrigin{ 0.0f, 0.0f }; // pivot point (0-1 normalized) + glm::vec2 mSize{ 1.0f, 1.0f }; + glm::mat4 mWorldMatrix{ 1.0f }; + bool mDirty{ true }; + + /// @brief Updates the world matrix based on current transform properties. + void updateWorldMatrix(); + + /// @brief Sets the position. + /// @param[ in ] position The new position. + void setPosition(const glm::vec2& position); + + /// @brief Sets the rotation. + /// @param[ in ] rotation The new rotation in degrees. + void setRotation(float rotation); + + /// @brief Sets the scale. + /// @param[ in ] scale The new scale. + void setScale(const glm::vec2& scale); + + /// @brief Sets the size. + /// @param[ in ] size The new size. + void setSize(const glm::vec2& size); + + /// @brief Sets the origin/pivot point (normalized 0-1). + /// @param[ in ] origin The new origin. + void setOrigin(const glm::vec2& origin); + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Sprite component for 2D rendering. + /// + /// Represents a textured quad that can be rendered with a texture. + //--------------------------------------------------------------------------------------------- + struct SEGFAULT_EXPORT SpriteComponent final { + core::guid mTextureHandle{ 0 }; + core::Rect mTextureRect{ 0, 0, 0, 0 }; + glm::vec4 mColor{ 1.0f, 1.0f, 1.0f, 1.0f }; + bool mFlipX{ false }; + bool mFlipY{ false }; + float mAlpha{ 1.0f }; + bool mVisible{ true }; + + /// @brief Default constructor. + SpriteComponent() = default; + + /// @brief Constructs a sprite component with a texture. + /// @param[ in ] textureHandle The handle to the texture. + explicit SpriteComponent(core::guid textureHandle); + + /// @brief Sets the texture handle. + /// @param[ in ] textureHandle The handle to the texture. + void setTexture(core::guid textureHandle); + + /// @brief Sets the color. + /// @param[ in ] color The color to apply to the sprite. + void setColor(const glm::vec4& color); + + /// @brief Sets the alpha value. + /// @param[ in ] alpha The alpha value (0.0 - 1.0). + void setAlpha(float alpha); + + /// @brief Sets the texture rectangle (for sprite sheets). + /// @param[ in ] rect The texture rectangle. + void setTextureRect(const core::Rect& rect); + + /// @brief Sets the flip flags. + /// @param[ in ] flipX True to flip horizontally. + /// @param[ in ] flipY True to flip vertically. + void setFlip(bool flipX, bool flipY); + + /// @brief Sets visibility. + /// @param[ in ] visible True to make visible, false to hide. + void setVisible(bool visible); + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Text component for 2D rendering. + /// + /// Represents text that can be rendered using a font. + //--------------------------------------------------------------------------------------------- + struct SEGFAULT_EXPORT TextComponent final { + std::string mText; + core::guid mFontHandle{ 0 }; + glm::vec4 mColor{ 1.0f, 1.0f, 1.0f, 1.0f }; + float mFontSize{ 16.0f }; + float mLineSpacing{ 1.0f }; + float mLetterSpacing{ 0.0f }; + bool mVisible{ true }; + bool mDirty{ true }; + + // Text alignment + enum class TextAlignment { + Left, + Center, + Right + }; + + enum class VerticalAlignment { + Top, + Middle, + Bottom + }; + + TextAlignment mHorizontalAlignment{ TextAlignment::Left }; + VerticalAlignment mVerticalAlignment{ VerticalAlignment::Top }; + + /// @brief Default constructor. + TextComponent() = default; + + /// @brief Constructs a text component with text and font. + /// @param[ in ] text The text to display. + /// @param[ in ] fontHandle The handle to the font. + TextComponent(const std::string& text, core::guid fontHandle); + + /// @brief Sets the text. + /// @param[ in ] text The text to display. + void setText(const std::string& text); + + /// @brief Sets the font handle. + /// @param[ in ] fontHandle The handle to the font. + void setFont(core::guid fontHandle); + + /// @brief Sets the color. + /// @param[ in ] color The color to apply to the text. + void setColor(const glm::vec4& color); + + /// @brief Sets the font size. + /// @param[ in ] fontSize The font size in points. + void setFontSize(float fontSize); + + /// @brief Sets the horizontal alignment. + /// @param[ in ] alignment The horizontal alignment. + void setHorizontalAlignment(TextAlignment alignment); + + /// @brief Sets the vertical alignment. + /// @param[ in ] alignment The vertical alignment. + void setVerticalAlignment(VerticalAlignment alignment); + + /// @brief Sets visibility. + /// @param[ in ] visible True to make visible, false to hide. + void setVisible(bool visible); + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Render component for 2D entities. + /// + /// Contains render-specific data like layer assignment and render order. + //--------------------------------------------------------------------------------------------- + struct SEGFAULT_EXPORT Render2DComponent final { + Layer2D* mLayer{ nullptr }; + int32_t mRenderOrder{ 0 }; + bool mVisible{ true }; + bool mCastShadows{ false }; + bool mReceiveShadows{ false }; + + /// @brief Default constructor. + Render2DComponent() = default; + + /// @brief Sets the layer. + /// @param[ in ] layer The layer this entity belongs to. + void setLayer(Layer2D* layer); + + /// @brief Sets the render order within the layer. + /// @param[ in ] order The render order (lower values render first). + void setRenderOrder(int32_t order); + + /// @brief Sets visibility. + /// @param[ in ] visible True to make visible, false to hide. + void setVisible(bool visible); + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Animation component for 2D entities. + /// + /// Supports frame-based animation for sprites. + //--------------------------------------------------------------------------------------------- + struct SEGFAULT_EXPORT Animation2DComponent final { + struct Frame final { + core::Rect mTextureRect; + float mDuration{ 0.1f }; // in seconds + }; + + std::vector mFrames; + uint32_t mCurrentFrame{ 0 }; + float mFrameTimer{ 0.0f }; + float mAnimationSpeed{ 1.0f }; + bool mPlaying{ false }; + bool mLoop{ true }; + bool mDirty{ true }; + + /// @brief Default constructor. + Animation2DComponent() = default; + + /// @brief Adds a frame to the animation. + /// @param[ in ] textureRect The texture rectangle for this frame. + /// @param[ in ] duration The duration of this frame in seconds. + void addFrame(const core::Rect& textureRect, float duration = 0.1f); + + /// @brief Sets the animation frames. + /// @param[ in ] frames The array of frames. + void setFrames(const std::vector& frames); + + /// @brief Plays the animation. + /// @param[ in ] loop True to loop the animation, false to play once. + void play(bool loop = true); + + /// @brief Stops the animation. + void stop(); + + /// @brief Pauses the animation. + void pause(); + + /// @brief Resumes the animation. + void resume(); + + /// @brief Updates the animation. + /// @param[ in ] deltaTime The time elapsed since the last frame. + void update(float deltaTime); + + /// @brief Gets the current frame's texture rectangle. + /// @return The texture rectangle of the current frame. + core::Rect getCurrentFrameRect() const; + + /// @brief Gets the current frame index. + /// @return The current frame index. + uint32_t getCurrentFrameIndex() const; + + /// @brief Sets the current frame index. + /// @param[ in ] frameIndex The frame index to set. + void setCurrentFrameIndex(uint32_t frameIndex); + + /// @brief Sets the animation speed. + /// @param[ in ] speed The animation speed multiplier. + void setAnimationSpeed(float speed); + + /// @brief Checks if the animation is playing. + /// @return True if playing, false otherwise. + bool isPlaying() const; + + /// @brief Checks if the animation is looped. + /// @return True if looped, false otherwise. + bool isLooping() const; + + /// @brief Gets the number of frames. + /// @return The number of frames. + uint32_t getFrameCount() const; + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Base class for all 2D scenes. + /// + /// Provides the foundation for creating custom 2D scenes with entities, layers, and rendering. + //--------------------------------------------------------------------------------------------- + class SEGFAULT_EXPORT Scene2D { + public: + /// @brief Constructs a new Scene2D. + Scene2D(); + + /// @brief Destroys the Scene2D. + virtual ~Scene2D(); + + /// @brief Initializes the scene. + /// @param[ in ] rhi The rendering hardware interface. + /// @return True if initialization was successful, false otherwise. + virtual bool init(renderer::RHI& rhi); + + /// @brief Shuts down the scene and releases all resources. + virtual void shutdown(); + + /// @brief Updates the scene. + /// @param[ in ] deltaTime The time elapsed since the last frame. + virtual void update(float deltaTime); + + /// @brief Renders the scene. + /// @param[ in ] rhi The rendering hardware interface. + virtual void render(renderer::RHI& rhi); + + /// @brief Called when the scene is activated. + virtual void onActivate(); + + /// @brief Called when the scene is deactivated. + virtual void onDeactivate(); + + /// @brief Called when the scene is loaded. + virtual void onLoad(); + + /// @brief Called when the scene is unloaded. + virtual void onUnload(); + + //----------------------------------------------------------------------------------------- + /// @brief Creates a new 2D entity. + /// @return A new entity handle. + //----------------------------------------------------------------------------------------- + Entity2D createEntity(); + + //----------------------------------------------------------------------------------------- + /// @brief Destroys an entity and all its components. + /// @param[ in ] entity The entity to destroy. + //----------------------------------------------------------------------------------------- + void destroyEntity(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Adds a transform component to an entity. + /// @param[ in ] entity The entity to add the component to. + /// @return Reference to the added component. + //----------------------------------------------------------------------------------------- + Transform2DComponent& addTransformComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Adds a sprite component to an entity. + /// @param[ in ] entity The entity to add the component to. + /// @return Reference to the added component. + //----------------------------------------------------------------------------------------- + SpriteComponent& addSpriteComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Adds a text component to an entity. + /// @param[ in ] entity The entity to add the component to. + /// @return Reference to the added component. + //----------------------------------------------------------------------------------------- + TextComponent& addTextComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Adds a render component to an entity. + /// @param[ in ] entity The entity to add the component to. + /// @return Reference to the added component. + //----------------------------------------------------------------------------------------- + Render2DComponent& addRenderComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Adds an animation component to an entity. + /// @param[ in ] entity The entity to add the component to. + /// @return Reference to the added component. + //----------------------------------------------------------------------------------------- + Animation2DComponent& addAnimationComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Gets a transform component from an entity. + /// @param[ in ] entity The entity to get the component from. + /// @return Pointer to the component, or nullptr if not found. + //----------------------------------------------------------------------------------------- + Transform2DComponent* getTransformComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Gets a sprite component from an entity. + /// @param[ in ] entity The entity to get the component from. + /// @return Pointer to the component, or nullptr if not found. + //----------------------------------------------------------------------------------------- + SpriteComponent* getSpriteComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Gets a text component from an entity. + /// @param[ in ] entity The entity to get the component from. + /// @return Pointer to the component, or nullptr if not found. + //----------------------------------------------------------------------------------------- + TextComponent* getTextComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Gets a render component from an entity. + /// @param[ in ] entity The entity to get the component from. + /// @return Pointer to the component, or nullptr if not found. + //----------------------------------------------------------------------------------------- + Render2DComponent* getRenderComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Gets an animation component from an entity. + /// @param[ in ] entity The entity to get the component from. + /// @return Pointer to the component, or nullptr if not found. + //----------------------------------------------------------------------------------------- + Animation2DComponent* getAnimationComponent(Entity2D entity); + + //----------------------------------------------------------------------------------------- + /// @brief Creates a new layer. + /// @param[ in ] name The name of the layer. + /// @return Pointer to the created layer, or nullptr if creation failed. + //----------------------------------------------------------------------------------------- + Layer2D* createLayer(const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Destroys a layer by name. + /// @param[ in ] name The name of the layer to destroy. + /// @return True if the layer was found and destroyed, false otherwise. + //----------------------------------------------------------------------------------------- + bool destroyLayer(const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Gets a layer by name. + /// @param[ in ] name The name of the layer to retrieve. + /// @return Pointer to the layer, or nullptr if not found. + //----------------------------------------------------------------------------------------- + Layer2D* getLayer(const std::string& name) const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the default layer. + /// @return Pointer to the default layer. + //----------------------------------------------------------------------------------------- + Layer2D* getDefaultLayer() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the main camera. + /// @return Reference to the main camera. + //----------------------------------------------------------------------------------------- + Camera2D& getMainCamera(); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the main camera (const version). + /// @return Const reference to the main camera. + //----------------------------------------------------------------------------------------- + const Camera2D& getMainCamera() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the viewport size. + /// @param[ in ] width The width of the viewport. + /// @param[ in ] height The height of the viewport. + //----------------------------------------------------------------------------------------- + void setViewportSize(uint32_t width, uint32_t height); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the viewport width. + /// @return The viewport width. + //----------------------------------------------------------------------------------------- + uint32_t getViewportWidth() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the viewport height. + /// @return The viewport height. + //----------------------------------------------------------------------------------------- + uint32_t getViewportHeight() const; + + //----------------------------------------------------------------------------------------- + /// @brief Checks if an entity is valid. + /// @param[ in ] entity The entity to check. + /// @return True if the entity is valid, false otherwise. + //----------------------------------------------------------------------------------------- + bool isValid(Entity2D entity) const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the scene name. + /// @return The scene name. + //----------------------------------------------------------------------------------------- + const std::string& getName() const; + + //----------------------------------------------------------------------------------------- + /// @brief Sets the scene name. + /// @param[ in ] name The scene name. + //----------------------------------------------------------------------------------------- + void setName(const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the scene manager. + /// @return Pointer to the scene manager, or nullptr if not assigned. + //----------------------------------------------------------------------------------------- + Scene2DManager* getManager() const; + + protected: + // Component storage using dense arrays with entity mapping + template + class ComponentPool2D { + public: + T& add(Entity2D entity) { + auto it = mEntityToIndex.find(entity.id); + if (it != mEntityToIndex.end()) { + return mDense[it->second]; + } + const uint32_t idx = static_cast(mDense.size()); + mEntityToIndex[entity.id] = idx; + mIndexToEntity.push_back(entity); + mDense.push_back(T{}); + return mDense[idx]; + } + + T* get(Entity2D entity) { + auto it = mEntityToIndex.find(entity.id); + return it == mEntityToIndex.end() ? nullptr : &mDense[it->second]; + } + + void remove(Entity2D entity) { + auto it = mEntityToIndex.find(entity.id); + if (it != mEntityToIndex.end()) { + uint32_t idx = it->second; + // Swap with last element for O(1) removal + if (idx < mDense.size() - 1) { + std::swap(mDense[idx], mDense.back()); + mEntityToIndex[mIndexToEntity.back().id] = idx; + mIndexToEntity[idx] = mIndexToEntity.back(); + } + mDense.pop_back(); + mIndexToEntity.pop_back(); + mEntityToIndex.erase(it); + } + } + + bool has(Entity2D entity) const { + return mEntityToIndex.find(entity.id) != mEntityToIndex.end(); + } + + std::vector& data() { return mDense; } + const std::vector& data() const { return mDense; } + + private: + std::vector mDense; + std::vector mIndexToEntity; + std::unordered_map mEntityToIndex; + }; + + ComponentPool2D mTransformPool; + ComponentPool2D mSpritePool; + ComponentPool2D mTextPool; + ComponentPool2D mRenderPool; + ComponentPool2D mAnimationPool; + + std::unordered_map> mLayers; + std::unique_ptr mDefaultLayer; + Camera2D mMainCamera; + std::string mName; + Scene2DManager* mManager{ nullptr }; + uint32_t mViewportWidth{ 0 }; + uint32_t mViewportHeight{ 0 }; + core::guid mNextEntityId{ 1 }; + + // Friend declaration for manager access + friend class Scene2DManager; + }; + + //--------------------------------------------------------------------------------------------- + /// @brief Simple 2D scene for basic rendering. + /// + /// A convenience class for creating simple 2D scenes without complex setup. + //--------------------------------------------------------------------------------------------- + class SEGFAULT_EXPORT SimpleScene2D : public Scene2D { + public: + /// @brief Constructs a new SimpleScene2D. + SimpleScene2D(); + + /// @brief Destroys the SimpleScene2D. + ~SimpleScene2D() = default; + + /// @brief Initializes the simple scene. + /// @param[ in ] rhi The rendering hardware interface. + /// @return True if initialization was successful, false otherwise. + bool init(renderer::RHI& rhi) override; + + /// @brief Creates a simple sprite entity. + /// @param[ in ] textureHandle The handle to the texture. + /// @param[ in ] position The position of the sprite. + /// @param[ in ] size The size of the sprite. + /// @return The created entity. + Entity2D createSprite(core::guid textureHandle, const glm::vec2& position, const glm::vec2& size); + }; + +} // namespace segfault::scene diff --git a/src/runtime/scene/scene2dmanager.cpp b/src/runtime/scene/scene2dmanager.cpp new file mode 100644 index 0000000..48700ab --- /dev/null +++ b/src/runtime/scene/scene2dmanager.cpp @@ -0,0 +1,297 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015-2026 Segfault by Kim Kulling + +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 "scene/scene2dmanager.h" +#include "scene/scene2d.h" +#include "renderer/RHI.h" + +#include + +namespace segfault::scene { + + //--------------------------------------------------------------------------------------------- + // Scene2DManager implementation + //--------------------------------------------------------------------------------------------- + + Scene2DManager::Scene2DManager() : mActiveScene(nullptr), mRHI(nullptr) { + // empty + } + + Scene2DManager::~Scene2DManager() { + shutdown(); + } + + bool Scene2DManager::init(renderer::RHI& rhi) { + if (mRHI != nullptr) { + return true; // Already initialized + } + + mRHI = &rhi; + mActiveScene = nullptr; + mScenes.clear(); + mRenderOrder.clear(); + + return true; + } + + bool Scene2DManager::shutdown() { + unloadAllScenes(); + mRHI = nullptr; + mActiveScene = nullptr; + mSceneFactories.clear(); + return true; + } + + Scene2D* Scene2DManager::createScene(const std::string& name, const std::string& sceneClassName) { + if (mScenes.find(name) != mScenes.end()) { + core::logMessage(core::LogType::Warn, ("Scene with name '" + name + "' already exists").c_str()); + return nullptr; + } + + auto factoryIt = mSceneFactories.find(sceneClassName); + if (factoryIt == mSceneFactories.end()) { + core::logMessage(core::LogType::Error, ("Scene factory for class '" + sceneClassName + "' not registered").c_str()); + return nullptr; + } + + Scene2D* newScene = factoryIt->second(); + if (newScene == nullptr) { + core::logMessage(core::LogType::Error, ("Failed to create scene of class '" + sceneClassName + "'").c_str()); + return nullptr; + } + + newScene->mName = name; + newScene->mManager = this; + + if (!newScene->init(*mRHI)) { + core::logMessage(core::LogType::Error, ("Failed to initialize scene '" + name + "'").c_str()); + delete newScene; + return nullptr; + } + + auto result = mScenes.emplace(name, std::unique_ptr(newScene)); + if (!result.second) { + core::logMessage(core::LogType::Error, ("Failed to emplace scene '" + name + "' into manager").c_str()); + delete newScene; + return nullptr; + } + + // If this is the first scene, activate it + if (mActiveScene == nullptr) { + mActiveScene = newScene; + mActiveScene->onActivate(); + } + + // Add to render order if not already present + if (std::find(mRenderOrder.begin(), mRenderOrder.end(), name) == mRenderOrder.end()) { + mRenderOrder.push_back(name); + } + + core::logMessage(core::LogType::Info, ("Created scene '" + name + "' of class '" + sceneClassName + "'").c_str()); + + return newScene; + } + + Scene2D* Scene2DManager::loadScene(const std::string& name, std::function factory) { + if (mScenes.find(name) != mScenes.end()) { + core::logMessage(core::LogType::Warn, ("Scene with name '" + name + "' already exists").c_str()); + return nullptr; + } + + if (factory == nullptr) { + core::logMessage(core::LogType::Error, "Scene factory function is null"); + return nullptr; + } + + Scene2D* newScene = factory(); + if (newScene == nullptr) { + core::logMessage(core::LogType::Error, ("Factory failed to create scene '" + name + "'").c_str()); + return nullptr; + } + + newScene->mName = name; + newScene->mManager = this; + + if (!newScene->init(*mRHI)) { + core::logMessage(core::LogType::Error, ("Failed to initialize scene '" + name + "'").c_str()); + delete newScene; + return nullptr; + } + + auto result = mScenes.emplace(name, std::unique_ptr(newScene)); + if (!result.second) { + core::logMessage(core::LogType::Error, ("Failed to emplace scene '" + name + "' into manager").c_str()); + delete newScene; + return nullptr; + } + + // If this is the first scene, activate it + if (mActiveScene == nullptr) { + mActiveScene = newScene; + mActiveScene->onActivate(); + } + + // Add to render order if not already present + if (std::find(mRenderOrder.begin(), mRenderOrder.end(), name) == mRenderOrder.end()) { + mRenderOrder.push_back(name); + } + + core::logMessage(core::LogType::Info, ("Loaded scene '" + name + "'").c_str()); + + return newScene; + } + + bool Scene2DManager::unloadScene(const std::string& name) { + auto it = mScenes.find(name); + if (it == mScenes.end()) { + core::logMessage(core::LogType::Warn, ("Scene '" + name + "' not found for unloading").c_str()); + return false; + } + + // Check if this scene is active + if (mActiveScene == it->second.get()) { + mActiveScene->onDeactivate(); + mActiveScene = nullptr; + } + + // Remove from render order + auto renderIt = std::find(mRenderOrder.begin(), mRenderOrder.end(), name); + if (renderIt != mRenderOrder.end()) { + mRenderOrder.erase(renderIt); + } + + // Shutdown and remove the scene + it->second->shutdown(); + mScenes.erase(it); + + core::logMessage(core::LogType::Info, ("Unloaded scene '" + name + "'").c_str()); + + return true; + } + + void Scene2DManager::unloadAllScenes() { + // Deactivate current scene first + mActiveScene = nullptr; + + // Shutdown and clear all scenes + for (auto& pair : mScenes) { + pair.second->shutdown(); + } + mScenes.clear(); + mRenderOrder.clear(); + + core::logMessage(core::LogType::Info, "Unloaded all scenes"); + } + + bool Scene2DManager::activateScene(const std::string& name) { + auto it = mScenes.find(name); + if (it == mScenes.end()) { + core::logMessage(core::LogType::Error, ("Scene '" + name + "' not found for activation").c_str()); + return false; + } + + if (mActiveScene != nullptr) { + mActiveScene->onDeactivate(); + } + + mActiveScene = it->second.get(); + mActiveScene->onActivate(); + + core::logMessage(core::LogType::Info, ("Activated scene '" + name + "'").c_str()); + + return true; + } + + void Scene2DManager::deactivateCurrentScene() { + if (mActiveScene != nullptr) { + mActiveScene->onDeactivate(); + mActiveScene = nullptr; + core::logMessage(core::LogType::Info, "Deactivated current scene"); + } + } + + Scene2D* Scene2DManager::getActiveScene() const { + return mActiveScene; + } + + Scene2D* Scene2DManager::getScene(const std::string& name) const { + auto it = mScenes.find(name); + if (it == mScenes.end()) { + return nullptr; + } + return it->second.get(); + } + + bool Scene2DManager::hasScene(const std::string& name) const { + return mScenes.find(name) != mScenes.end(); + } + + void Scene2DManager::update(float deltaTime) { + // Update all loaded scenes + for (auto& pair : mScenes) { + pair.second->update(deltaTime); + } + } + + void Scene2DManager::render(renderer::RHI& rhi) { + if (mActiveScene != nullptr) { + mActiveScene->render(rhi); + } + } + + void Scene2DManager::renderScene(renderer::RHI& rhi, const std::string& name) { + auto it = mScenes.find(name); + if (it != mScenes.end()) { + it->second->render(rhi); + } + } + + void Scene2DManager::setRenderOrder(const std::vector& sceneNames) { + mRenderOrder = sceneNames; + + // Verify all scenes in render order exist + for (const auto& name : mRenderOrder) { + if (mScenes.find(name) == mScenes.end()) { + core::logMessage(core::LogType::Warn, ("Scene '" + name + "' in render order does not exist").c_str()); + } + } + } + + std::vector Scene2DManager::getSceneNames() const { + std::vector names; + for (const auto& pair : mScenes) { + names.push_back(pair.first); + } + return names; + } + + uint32_t Scene2DManager::getSceneCount() const { + return static_cast(mScenes.size()); + } + + void Scene2DManager::registerSceneFactory(const std::string& className, std::function factory) { + mSceneFactories[className] = factory; + core::logMessage(core::LogType::Info, ("Registered scene factory for class '" + className + "'").c_str()); + } + +} // namespace segfault::scene diff --git a/src/runtime/scene/scene2dmanager.h b/src/runtime/scene/scene2dmanager.h new file mode 100644 index 0000000..2b656f9 --- /dev/null +++ b/src/runtime/scene/scene2dmanager.h @@ -0,0 +1,187 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2015-2026 Segfault by Kim Kulling + +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 "core/segfault.h" +#include "scene/scene2d.h" + +#include +#include +#include +#include + +namespace segfault::scene { + + // Forward declarations + class Scene2D; + + //--------------------------------------------------------------------------------------------- + /// @class Scene2DManager + /// @brief Manages multiple 2D scenes, providing loading, unloading, activation, and rendering services. + /// + /// The Scene2DManager is the central point for handling all 2D rendering scenes in the engine. + /// It maintains a collection of scenes, manages scene transitions, and coordinates rendering. + //--------------------------------------------------------------------------------------------- + class SEGFAULT_EXPORT Scene2DManager final { + public: + /// @brief Constructs a new Scene2DManager. + Scene2DManager(); + + /// @brief Destroys the Scene2DManager and all loaded scenes. + ~Scene2DManager(); + + /// @brief Deleted copy constructor. + Scene2DManager(const Scene2DManager&) = delete; + + /// @brief Deleted copy assignment operator. + Scene2DManager& operator=(const Scene2DManager&) = delete; + + //----------------------------------------------------------------------------------------- + /// @brief Initializes the scene manager. + /// @param[ in ] rhi The rendering hardware interface to use. + /// @return True if initialization was successful, false otherwise. + //----------------------------------------------------------------------------------------- + bool init(renderer::RHI& rhi); + + //----------------------------------------------------------------------------------------- + /// @brief Shuts down the scene manager and releases all resources. + /// @return True if shutdown was successful, false otherwise. + //----------------------------------------------------------------------------------------- + bool shutdown(); + + //----------------------------------------------------------------------------------------- + /// @brief Creates and loads a new 2D scene. + /// @param[ in ] name The unique name of the scene. + /// @param[ in ] sceneClassName The class name of the scene to instantiate. + /// @return Pointer to the created scene, or nullptr if creation failed. + //----------------------------------------------------------------------------------------- + Scene2D* createScene(const std::string& name, const std::string& sceneClassName); + + //----------------------------------------------------------------------------------------- + /// @brief Loads a 2D scene from a custom factory function. + /// @param[ in ] name The unique name of the scene. + /// @param[ in ] factory Function that creates and returns a Scene2D pointer. + /// @return Pointer to the loaded scene, or nullptr if loading failed. + //----------------------------------------------------------------------------------------- + Scene2D* loadScene(const std::string& name, std::function factory); + + //----------------------------------------------------------------------------------------- + /// @brief Unloads a scene by name. + /// @param[ in ] name The name of the scene to unload. + /// @return True if the scene was found and unloaded, false otherwise. + //----------------------------------------------------------------------------------------- + bool unloadScene(const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Unloads all loaded scenes. + //----------------------------------------------------------------------------------------- + void unloadAllScenes(); + + //----------------------------------------------------------------------------------------- + /// @brief Activates a scene for rendering and updates. + /// @param[ in ] name The name of the scene to activate. + /// @return True if the scene was found and activated, false otherwise. + //----------------------------------------------------------------------------------------- + bool activateScene(const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Deactivates the currently active scene. + //----------------------------------------------------------------------------------------- + void deactivateCurrentScene(); + + //----------------------------------------------------------------------------------------- + /// @brief Gets the currently active scene. + /// @return Pointer to the active scene, or nullptr if no scene is active. + //----------------------------------------------------------------------------------------- + Scene2D* getActiveScene() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the currently active scene by name. + /// @param[ in ] name The name of the scene to retrieve. + /// @return Pointer to the scene, or nullptr if not found. + //----------------------------------------------------------------------------------------- + Scene2D* getScene(const std::string& name) const; + + //----------------------------------------------------------------------------------------- + /// @brief Checks if a scene with the given name exists. + /// @param[ in ] name The name of the scene to check. + /// @return True if the scene exists, false otherwise. + //----------------------------------------------------------------------------------------- + bool hasScene(const std::string& name) const; + + //----------------------------------------------------------------------------------------- + /// @brief Updates all loaded scenes. + /// @param[ in ] deltaTime The time elapsed since the last frame in seconds. + //----------------------------------------------------------------------------------------- + void update(float deltaTime); + + //----------------------------------------------------------------------------------------- + /// @brief Renders the active scene. + /// @param[ in ] rhi The rendering hardware interface to use. + //----------------------------------------------------------------------------------------- + void render(renderer::RHI& rhi); + + //----------------------------------------------------------------------------------------- + /// @brief Renders a specific scene by name. + /// @param[ in ] rhi The rendering hardware interface to use. + /// @param[ in ] name The name of the scene to render. + //----------------------------------------------------------------------------------------- + void renderScene(renderer::RHI& rhi, const std::string& name); + + //----------------------------------------------------------------------------------------- + /// @brief Sets the rendering order for scenes. + /// @param[ in ] sceneNames Array of scene names in the desired rendering order. + //----------------------------------------------------------------------------------------- + void setRenderOrder(const std::vector& sceneNames); + + //----------------------------------------------------------------------------------------- + /// @brief Gets all loaded scene names. + /// @return Array of all loaded scene names. + //----------------------------------------------------------------------------------------- + std::vector getSceneNames() const; + + //----------------------------------------------------------------------------------------- + /// @brief Gets the number of loaded scenes. + /// @return The number of loaded scenes. + //----------------------------------------------------------------------------------------- + uint32_t getSceneCount() const; + + //----------------------------------------------------------------------------------------- + /// @brief Registers a scene factory function for a specific scene class name. + /// @param[ in ] className The class name to register the factory for. + /// @param[ in ] factory The factory function that creates scenes of this type. + //----------------------------------------------------------------------------------------- + void registerSceneFactory(const std::string& className, std::function factory); + + private: + using SceneMap = std::unordered_map>; + using SceneFactoryMap = std::unordered_map>; + + SceneMap mScenes; + SceneFactoryMap mSceneFactories; + Scene2D* mActiveScene{ nullptr }; + std::vector mRenderOrder; + renderer::RHI* mRHI{ nullptr }; + }; + +} // namespace segfault::scene diff --git a/src/tools/assetbaker/CMakeLists.txt b/src/tools/assetbaker/CMakeLists.txt index 28190ea..4639698 100644 --- a/src/tools/assetbaker/CMakeLists.txt +++ b/src/tools/assetbaker/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(assetbaker main.cpp) target_link_libraries(assetbaker segfault_runtime nlohmann_json::nlohmann_json) +add_dependencies(assetbaker compile_all_assets) set_target_properties(assetbaker PROPERTIES FOLDER tools\\assetbaker )