diff --git a/README.md b/README.md index 065dba77..b1b164a0 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ This engine started as a C++ training project, with hopes of being applied in my | **Data** | - File formats:
    - Meshes:
        - GLTF 2.0 (using [fastgltf](https://github.com/spnda/fastgltf))
        - OBJ (using ???)
- Images:
        - PNG, JPEG, BMP, TGA, GIF (using [stb](https://github.com/nothings/stb))
        - SVG (using [lunasvg](https://github.com/sammycage/lunasvg))
        - WEBP (using [libwebp](https://github.com/webmproject/libwebp))
        - WEBM (video only) (using [libwebm](https://github.com/webmproject/libwebm))
- Fonts:
        - TTF (using [stb](https://github.com/nothings/stb))
- Audio (using [BASS](https://www.un4seen.com/)):
        - OGG
        - MP4
        - MP3
        - WAV
        - Supports url audio
- JSON (using [glaze](https://github.com/stephenberry/glaze)) | | **Math** | - Vectors, colors, matrices & quaternions support
- Bezier curve & easing
- Packing support (float16, etc) | | **Physics** | - 3D multi-threaded physics (using [JoltPhysics](https://github.com/jrouwe/JoltPhysics))
- 2D physics support (using [Muli](https://github.com/Sopiro/Muli)) | -| **Rendering** | - **Vulkan** & **DirectX 12** support using ([Diligent](https://github.com/DiligentGraphics/DiligentCore))
- Material system similar to unity
- Window & Input callbacks (using [GLFW](https://github.com/glfw/glfw))
- Clustered rendering :
        - Decals (**WIP**)
        - Lights (point / spot/ directional)
- Linux (**steamdeck**) support
- Bindless rendering
- Post-processing support
- 2D rendering
- Custom rendering plugins
- GPU Picking
- [IMGUI](https://github.com/ocornut/imgui) support
- GPU Particle system
| +| **Rendering** | - **Vulkan** & **DirectX 12** support using ([Diligent](https://github.com/DiligentGraphics/DiligentCore))
- Material system similar to unity
- Window & Input callbacks (using [GLFW](https://github.com/glfw/glfw))
- Clustered rendering :
        - Decals (**WIP**)
        - Lights (point / spot/ directional)
- Linux (**steamdeck**) support
- Bindless rendering
- Post-processing support
- 2D rendering
- Custom rendering plugins
- Multiple camera support
- GPU Picking
- [IMGUI](https://github.com/ocornut/imgui) support
- GPU Particle system
| | **Network** | - HTTP / HTTPS requests (using [libcpr](https://github.com/libcpr/cpr))
- Packet network implementation
- **NetVar** & **NetArray** support for [snapshot](https://gafferongames.com/post/snapshot_interpolation/) implementation
- Simple socket implementation | | **Scripting** | - Scripting / modding support with LUAU (using [luabridge3](https://github.com/kunitoki/LuaBridge3) + [luau](https://github.com/luau-lang/luau)) | | **Other** | - I18N (internationalization) support
- Settings support
- Steamworks support
- Custom UI
- DEV Console with support for custom commands & scripts
- Timer utils (based on [GMOD's](https://wiki.facepunch.com/gmod/timer) timers)
- File watcher implementation
- Threading utilities | @@ -55,7 +55,7 @@ This engine started as a C++ training project, with hopes of being applied in my | 007-particle-system
| 008-ui
| 009-gltf
| | 010-bass-audio
| 011-physics-3D
| 012-physics-2D
| | 013-webm
| 014-scripting
| 015-gpu-picking
| -| 016-steamworks
| 017-imgui
| | +| 016-steamworks
| 017-imgui
| 018-camera
| # BUILDING diff --git a/rawrbox.render/include/rawrbox/render/bindless.hpp b/rawrbox.render/include/rawrbox/render/bindless.hpp index 1b9e80a6..065e0419 100644 --- a/rawrbox.render/include/rawrbox/render/bindless.hpp +++ b/rawrbox.render/include/rawrbox/render/bindless.hpp @@ -62,7 +62,6 @@ namespace rawrbox { // SIGNATURES ------ static void createSignatures(); - static void bindSignatures(); // ----------------- static uint32_t internalRegister(Diligent::ITextureView* view, rawrbox::TEXTURE_TYPE type); @@ -80,6 +79,10 @@ namespace rawrbox { static void update(); + // SIGNATURES + static void bindSignatures(); + // ---------------- + // TEXTURES ------- static void registerTexture(rawrbox::TextureBase& texture); static void registerTexture(rawrbox::TextureRender& texture); diff --git a/rawrbox.render/include/rawrbox/render/cameras/base.hpp b/rawrbox.render/include/rawrbox/render/cameras/base.hpp index 4e746a12..81bafef6 100644 --- a/rawrbox.render/include/rawrbox/render/cameras/base.hpp +++ b/rawrbox.render/include/rawrbox/render/cameras/base.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -11,6 +13,9 @@ #include +#define CREATE_FLAGS(name, value) \ + const uint32_t name = 1 << value; + namespace rawrbox { struct CameraStaticUniforms { // Uniforms that won't be updated that frequently rawrbox::Matrix4x4 gProjection = {}; @@ -26,6 +31,12 @@ namespace rawrbox { bool operator!=(const CameraStaticUniforms& other) const { return !operator==(other); } }; + namespace CameraLayers { + // USER DEFINED + RB_RENDER_CAMERA_LAYERS(CREATE_FLAGS) + // ------------ + }; // namespace CameraLayers + struct CameraUniforms { rawrbox::Matrix4x4 gView = {}; rawrbox::Matrix4x4 gViewInv = {}; @@ -47,6 +58,8 @@ namespace rawrbox { class CameraBase { protected: + bool _enabled = true; + rawrbox::Vector3f _pos = {}; rawrbox::Vector4f _angle = {}; @@ -55,12 +68,15 @@ namespace rawrbox { rawrbox::Matrix4x4 _world = {}; + uint32_t _layers = 0; // None by default, it's up to the user to use this or not + + // Renderer ---- + std::unique_ptr _renderTarget = nullptr; + // -------------------------- + float _z_near = 0.01F; float _z_far = 100.F; - Diligent::RefCntAutoPtr _staticUniforms; - Diligent::RefCntAutoPtr _uniforms; - // LOGGER ------ std::unique_ptr _logger = std::make_unique("RawrBox-Camera"); // ------------- @@ -69,13 +85,15 @@ namespace rawrbox { virtual rawrbox::CameraStaticUniforms getStaticData(); public: - virtual ~CameraBase(); + static Diligent::RefCntAutoPtr staticUniforms; + static Diligent::RefCntAutoPtr uniforms; - CameraBase() = default; + CameraBase(const rawrbox::Vector2u& renderSize, bool depth = true); CameraBase(CameraBase&&) = default; CameraBase& operator=(CameraBase&&) = default; CameraBase(const CameraBase&) = delete; CameraBase& operator=(const CameraBase&) = delete; + virtual ~CameraBase(); // UTILS ----- virtual void setPos(const rawrbox::Vector3f& pos); @@ -100,12 +118,26 @@ namespace rawrbox { [[nodiscard]] virtual rawrbox::Vector3f worldToScreen(const rawrbox::Vector3f& pos) const; [[nodiscard]] virtual rawrbox::Vector3f screenToWorld(const rawrbox::Vector2f& screen_pos, const rawrbox::Vector3f& origin = {0, 0, 0}) const; + + virtual bool isEnabled() const; + virtual void setEnabled(bool enabled); + + virtual uint32_t getLayers() const; + virtual void setLayers(uint32_t layers); + virtual bool shouldRenderLayer(uint32_t layer) const; // ---------------- - [[nodiscard]] virtual Diligent::IBuffer* uniforms() const; - [[nodiscard]] virtual Diligent::IBuffer* staticUniforms() const; + // RENDER TARGET ---- + virtual void begin(); + virtual void end(); + + [[nodiscard]] virtual Diligent::ITextureView* getDepth() const; + [[nodiscard]] virtual Diligent::ITextureView* getColor(bool rt = false) const; + [[nodiscard]] virtual rawrbox::TextureRender* getRenderTarget() const; + // ------------ virtual void initialize(); + virtual void upload(); virtual void updateBuffer(); virtual void update(); diff --git a/rawrbox.render/include/rawrbox/render/cameras/perspective.hpp b/rawrbox.render/include/rawrbox/render/cameras/perspective.hpp index ecb5b05f..1c6489c1 100644 --- a/rawrbox.render/include/rawrbox/render/cameras/perspective.hpp +++ b/rawrbox.render/include/rawrbox/render/cameras/perspective.hpp @@ -8,9 +8,7 @@ namespace rawrbox { class CameraPerspective : public rawrbox::CameraBase { protected: - rawrbox::Vector2u _winSize = {}; float _FOV = 60.F; - void updateMtx() override; public: @@ -20,7 +18,7 @@ namespace rawrbox { CameraPerspective& operator=(CameraPerspective&&) = default; ~CameraPerspective() override = default; - explicit CameraPerspective(const rawrbox::Vector2u& winSize, float FOV = 60.F, float near = 0.01F, float far = 100.F); + explicit CameraPerspective(const rawrbox::Vector2u& renderSize, float FOV = 60.F, float near = 0.01F, float far = 100.F, bool depth = true); [[nodiscard]] rawrbox::Vector3f worldToScreen(const rawrbox::Vector3f& pos) const override; [[nodiscard]] rawrbox::Vector3f screenToWorld(const rawrbox::Vector2f& screenPos, const rawrbox::Vector3f& origin = {0, 0, 0}) const override; diff --git a/rawrbox.render/include/rawrbox/render/plugins/base.hpp b/rawrbox.render/include/rawrbox/render/plugins/base.hpp index 96a7b7e1..a1912f53 100644 --- a/rawrbox.render/include/rawrbox/render/plugins/base.hpp +++ b/rawrbox.render/include/rawrbox/render/plugins/base.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -40,8 +41,8 @@ namespace rawrbox { virtual void resize(const rawrbox::Vector2u& renderSize); virtual void upload(); - virtual void preRender(); - virtual void postRender(rawrbox::TextureRender& renderTarget); + virtual void preRender(const rawrbox::CameraBase& camera); + virtual void postRender(const rawrbox::CameraBase& camera); virtual void update(); diff --git a/rawrbox.render/include/rawrbox/render/plugins/clustered.hpp b/rawrbox.render/include/rawrbox/render/plugins/clustered.hpp index bb537e7b..da8d8a5d 100644 --- a/rawrbox.render/include/rawrbox/render/plugins/clustered.hpp +++ b/rawrbox.render/include/rawrbox/render/plugins/clustered.hpp @@ -71,7 +71,7 @@ namespace rawrbox { void signatures(std::vector& sig) override; void bindStatic(Diligent::IPipelineResourceSignature& sig) override; - void preRender() override; + void preRender(const rawrbox::CameraBase& camera) override; std::string getID() override; }; diff --git a/rawrbox.render/include/rawrbox/render/plugins/particle_engine.hpp b/rawrbox.render/include/rawrbox/render/plugins/particle_engine.hpp index a757b800..fa38bab7 100644 --- a/rawrbox.render/include/rawrbox/render/plugins/particle_engine.hpp +++ b/rawrbox.render/include/rawrbox/render/plugins/particle_engine.hpp @@ -50,7 +50,7 @@ namespace rawrbox { void signatures(std::vector& sig) override; void bindStatic(Diligent::IPipelineResourceSignature& sig) override; - void preRender() override; + void preRender(const rawrbox::CameraBase& camera) override; [[nodiscard]] Diligent::IPipelineResourceSignature* getSignature(bool dynamic = true) const; [[nodiscard]] Diligent::IShaderResourceBinding* getBind(bool dynamic = true) const; diff --git a/rawrbox.render/include/rawrbox/render/plugins/post_process.hpp b/rawrbox.render/include/rawrbox/render/plugins/post_process.hpp index 076ba70d..30aa4cb8 100644 --- a/rawrbox.render/include/rawrbox/render/plugins/post_process.hpp +++ b/rawrbox.render/include/rawrbox/render/plugins/post_process.hpp @@ -25,7 +25,7 @@ namespace rawrbox { void signatures(std::vector& sig) override; void bindStatic(Diligent::IPipelineResourceSignature& sig) override; - void postRender(rawrbox::TextureRender& render) override; + void postRender(const rawrbox::CameraBase& camera) override; // PLUGIN UTILS ---- template diff --git a/rawrbox.render/include/rawrbox/render/render_config.hpp b/rawrbox.render/include/rawrbox/render/render_config.hpp index a89e70bf..659f8803 100644 --- a/rawrbox.render/include/rawrbox/render/render_config.hpp +++ b/rawrbox.render/include/rawrbox/render/render_config.hpp @@ -40,3 +40,10 @@ #define RB_RENDER_THREAD_GROUP_SIZE (RB_RENDER_CLUSTERS_X_THREADS * RB_RENDER_CLUSTERS_Y_THREADS * RB_RENDER_CLUSTERS_Z_THREADS) // ---------------- + +// CAMERA ----- +// Add more layers if needed, you can then check if the camera should draw your model by checking if the layer is enabled +#define RB_RENDER_CAMERA_LAYERS(flag) \ + flag(LAYER_1, 1) \ + flag(LAYER_2, 2) +// ---------------- diff --git a/rawrbox.render/include/rawrbox/render/renderer.hpp b/rawrbox.render/include/rawrbox/render/renderer.hpp index 39fe6e02..1367d842 100644 --- a/rawrbox.render/include/rawrbox/render/renderer.hpp +++ b/rawrbox.render/include/rawrbox/render/renderer.hpp @@ -43,10 +43,6 @@ namespace rawrbox { std::map> _renderPlugins = {}; // -------------- - // Post process renderer ---- - std::unique_ptr _render = nullptr; - // -------------------------- - #ifdef _DEBUG // QUERIES --- std::unordered_map> _query = {}; @@ -64,8 +60,8 @@ namespace rawrbox { std::map _introList = {{"./assets/textures/rawrbox.webp", {1.4F, false}}}; // rawrbox intro, always the first //---- - std::function _drawCall = nullptr; - std::function _tempRender = nullptr; + std::function _drawCall = nullptr; + std::function _tempRender = nullptr; rawrbox::Colorf _clearColor = rawrbox::Colors::Black(); @@ -88,11 +84,14 @@ namespace rawrbox { // OTHER HANDLES std::unique_ptr _logger = std::make_unique("RawrBox-Renderer"); - std::unique_ptr _camera = nullptr; std::unique_ptr _stencil = nullptr; std::unique_ptr _GPUBlit = nullptr; // ------------- + // CAMERAS --- + std::vector> _cameras = {}; + // ---------- + // INTRO ------ virtual void playIntro(); virtual void introComplete(); @@ -151,7 +150,7 @@ namespace rawrbox { [[nodiscard]] virtual const std::map>& getPlugins() const; // ----------------------------------- - virtual void setDrawCall(std::function call); + virtual void setDrawCall(std::function call); virtual void update(); virtual void render(); @@ -163,15 +162,17 @@ namespace rawrbox { // CAMERA ------ template - T* setupCamera(CallbackArgs&&... args) { - this->_camera = std::make_unique(std::forward(args)...); - this->setMainCamera(this->_camera.get()); + T* createCamera(CallbackArgs&&... args) { + if (this->_initialized) CRITICAL_RAWRBOX("'createCamera' must be called before initializing the renderer!"); + auto camera = std::make_unique(std::forward(args)...); - return dynamic_cast(this->_camera.get()); + auto cameraPtr = camera.get(); + this->_cameras.push_back(std::move(camera)); + return dynamic_cast(cameraPtr); } - virtual void setMainCamera(rawrbox::CameraBase* camera) const; - [[nodiscard]] virtual rawrbox::CameraBase* camera() const; + virtual void setActiveCamera(rawrbox::CameraBase* camera) const; + [[nodiscard]] virtual rawrbox::CameraBase* getActiveCamera() const; // ---------------- // Utils ---- @@ -184,9 +185,6 @@ namespace rawrbox { // WARNING: NOT THREAD SAFE!! [[nodiscard]] virtual Diligent::IRenderDevice* device() const; - [[nodiscard]] virtual Diligent::ITextureView* getDepth() const; - [[nodiscard]] virtual Diligent::ITextureView* getColor(bool rt = false) const; - [[nodiscard]] virtual std::filesystem::path getShadersDirectory() const; [[nodiscard]] virtual const Diligent::RENDER_DEVICE_TYPE& getRenderType() const; diff --git a/rawrbox.render/src/bindless.cpp b/rawrbox.render/src/bindless.cpp index cc9c7b00..38d53630 100644 --- a/rawrbox.render/src/bindless.cpp +++ b/rawrbox.render/src/bindless.cpp @@ -85,11 +85,7 @@ namespace rawrbox { // Create signatures ------ createSignatures(); - // ------------- - - // Bind signatures ------ - bindSignatures(); - // ------------- + // ------------ } void BindlessManager::shutdown() { @@ -111,8 +107,6 @@ namespace rawrbox { // SIGNATURES --------- void BindlessManager::createSignatures() { auto* renderer = rawrbox::RENDERER; - - auto* camera = renderer->camera(); auto* device = renderer->device(); Diligent::PipelineResourceSignatureDesc PRSDesc; @@ -127,12 +121,9 @@ namespace rawrbox { {Diligent::SHADER_TYPE_PIXEL, "Constants", 1, Diligent::SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, Diligent::SHADER_RESOURCE_VARIABLE_TYPE_STATIC}, {Diligent::SHADER_TYPE_PIXEL, "g_Textures", RB_RENDER_MAX_TEXTURES, Diligent::SHADER_RESOURCE_TYPE_TEXTURE_SRV, Diligent::SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, Diligent::PIPELINE_RESOURCE_FLAG_RUNTIME_ARRAY}, - }; - if (camera != nullptr) { - resources.emplace_back(Diligent::SHADER_TYPE_VERTEX | Diligent::SHADER_TYPE_PIXEL | Diligent::SHADER_TYPE_GEOMETRY, "Camera", 1, Diligent::SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, Diligent::SHADER_RESOURCE_VARIABLE_TYPE_STATIC, Diligent::PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS); - resources.emplace_back(Diligent::SHADER_TYPE_VERTEX | Diligent::SHADER_TYPE_PIXEL | Diligent::SHADER_TYPE_GEOMETRY, "SCamera", 1, Diligent::SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, Diligent::SHADER_RESOURCE_VARIABLE_TYPE_STATIC, Diligent::PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS); - } + {Diligent::SHADER_TYPE_VERTEX | Diligent::SHADER_TYPE_PIXEL | Diligent::SHADER_TYPE_GEOMETRY, "Camera", 1, Diligent::SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, Diligent::SHADER_RESOURCE_VARIABLE_TYPE_STATIC, Diligent::PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS}, + {Diligent::SHADER_TYPE_VERTEX | Diligent::SHADER_TYPE_PIXEL | Diligent::SHADER_TYPE_GEOMETRY, "SCamera", 1, Diligent::SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, Diligent::SHADER_RESOURCE_VARIABLE_TYPE_STATIC, Diligent::PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS}}; // Add extra signatures ---- for (const auto& plugin : renderer->getPlugins()) { @@ -162,22 +153,17 @@ namespace rawrbox { } void BindlessManager::bindSignatures() { - auto* renderer = rawrbox::RENDERER; - auto* camera = renderer->camera(); - // Setup graphic binds --- signature->GetStaticVariableByName(Diligent::SHADER_TYPE_VERTEX, "Constants")->Set(signatureBufferVertex); signature->GetStaticVariableByName(Diligent::SHADER_TYPE_VERTEX, "SkinnedConstants")->Set(signatureBufferVertexSkinned); - if (camera != nullptr) { - signature->GetStaticVariableByName(Diligent::SHADER_TYPE_VERTEX, "Camera")->Set(camera->uniforms()); - signature->GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "Camera")->Set(camera->uniforms()); - signature->GetStaticVariableByName(Diligent::SHADER_TYPE_GEOMETRY, "Camera")->Set(camera->uniforms()); + signature->GetStaticVariableByName(Diligent::SHADER_TYPE_VERTEX, "Camera")->Set(rawrbox::CameraBase::uniforms); + signature->GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "Camera")->Set(rawrbox::CameraBase::uniforms); + signature->GetStaticVariableByName(Diligent::SHADER_TYPE_GEOMETRY, "Camera")->Set(rawrbox::CameraBase::uniforms); - signature->GetStaticVariableByName(Diligent::SHADER_TYPE_VERTEX, "SCamera")->Set(camera->staticUniforms()); - signature->GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "SCamera")->Set(camera->staticUniforms()); - signature->GetStaticVariableByName(Diligent::SHADER_TYPE_GEOMETRY, "SCamera")->Set(camera->staticUniforms()); - } + signature->GetStaticVariableByName(Diligent::SHADER_TYPE_VERTEX, "SCamera")->Set(rawrbox::CameraBase::staticUniforms); + signature->GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "SCamera")->Set(rawrbox::CameraBase::staticUniforms); + signature->GetStaticVariableByName(Diligent::SHADER_TYPE_GEOMETRY, "SCamera")->Set(rawrbox::CameraBase::staticUniforms); signature->GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "Constants")->Set(signatureBufferPixel); // ------------ diff --git a/rawrbox.render/src/cameras/base.cpp b/rawrbox.render/src/cameras/base.cpp index 3846f0b8..c9ad421b 100644 --- a/rawrbox.render/src/cameras/base.cpp +++ b/rawrbox.render/src/cameras/base.cpp @@ -5,45 +5,65 @@ #include namespace rawrbox { - CameraBase::~CameraBase() { - RAWRBOX_DESTROY(this->_uniforms); - RAWRBOX_DESTROY(this->_staticUniforms); + Diligent::RefCntAutoPtr CameraBase::staticUniforms; + Diligent::RefCntAutoPtr CameraBase::uniforms; + + CameraBase::CameraBase(const rawrbox::Vector2u& renderSize, bool depth) { + this->_renderTarget = std::make_unique(renderSize, depth); } + CameraBase::~CameraBase() { this->_renderTarget.reset(); } + void CameraBase::initialize() { - if (this->_staticUniforms != nullptr) CRITICAL_RAWRBOX("Camera already initialized!"); - { - auto staticData = this->getStaticData(); + if (this->_renderTarget == nullptr) CRITICAL_RAWRBOX("Render target not initialized!"); + this->_renderTarget->upload(Diligent::TEX_FORMAT_RGBA8_UNORM); + + // ADD GPU PICKING TEXTURE + auto idIndex = this->_renderTarget->addTexture(Diligent::TEX_FORMAT_RGBA8_UNORM); + this->_renderTarget->addView(idIndex, Diligent::TEXTURE_VIEW_RENDER_TARGET); + // -------- + } + + void CameraBase::upload() { + if (rawrbox::RENDERER == nullptr) CRITICAL_RAWRBOX("Renderer not initialized!"); - Diligent::BufferDesc CBDesc; - CBDesc.Name = "rawrbox::Camera::Static::Uniforms"; - CBDesc.Usage = Diligent::USAGE_IMMUTABLE; - CBDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER; - CBDesc.Size = sizeof(rawrbox::CameraStaticUniforms); + auto* device = rawrbox::RENDERER->device(); + if (device == nullptr) CRITICAL_RAWRBOX("Device not initialized!"); - Diligent::BufferData bData; - bData.DataSize = CBDesc.Size; - bData.pData = &staticData; + // These are shared across all the cameras. For performance reasons, we won't support different cameras (for now) + if (staticUniforms != nullptr || uniforms != nullptr) CRITICAL_RAWRBOX("Camera buffers already initialized!"); + auto staticData = this->getStaticData(); - rawrbox::RENDERER->device()->CreateBuffer(CBDesc, &bData, &this->_staticUniforms); - } + // STATIC BUFFER --- + Diligent::BufferDesc StaticDesc; + StaticDesc.Name = "rawrbox::Camera::Static::Uniforms"; + StaticDesc.Usage = Diligent::USAGE_IMMUTABLE; + StaticDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER; + StaticDesc.Size = sizeof(rawrbox::CameraStaticUniforms); - { - Diligent::BufferDesc CBDesc; - CBDesc.Name = "rawrbox::Camera::Uniforms"; - CBDesc.Usage = Diligent::USAGE_DEFAULT; - CBDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER; - CBDesc.Size = sizeof(rawrbox::CameraUniforms); + Diligent::BufferData sData; + sData.DataSize = StaticDesc.Size; + sData.pData = &staticData; - rawrbox::RENDERER->device()->CreateBuffer(CBDesc, nullptr, &this->_uniforms); - } + device->CreateBuffer(StaticDesc, &sData, &staticUniforms); + // ------------ + + // DYNAMIC BUFFER --- + Diligent::BufferDesc CBDesc; + CBDesc.Name = "rawrbox::Camera::Uniforms"; + CBDesc.Usage = Diligent::USAGE_DEFAULT; + CBDesc.BindFlags = Diligent::BIND_UNIFORM_BUFFER; + CBDesc.Size = sizeof(rawrbox::CameraUniforms); + + device->CreateBuffer(CBDesc, nullptr, &uniforms); + // ------------ // BARRIER ----- - rawrbox::BarrierUtils::barrier({{this->_staticUniforms, Diligent::RESOURCE_STATE_UNKNOWN, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}, - {this->_uniforms, Diligent::RESOURCE_STATE_UNKNOWN, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}}); + rawrbox::BarrierUtils::barrier({{staticUniforms, Diligent::RESOURCE_STATE_UNKNOWN, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}, + {uniforms, Diligent::RESOURCE_STATE_UNKNOWN, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}}); // ----------- - this->_logger->info("Initializing camera"); + this->_logger->info("Initializing camera buffers"); } void CameraBase::updateMtx() { CRITICAL_RAWRBOX("Not implemented"); }; @@ -134,8 +154,41 @@ namespace rawrbox { this->updateBuffer(); } + rawrbox::Vector3f CameraBase::worldToScreen(const rawrbox::Vector3f& /*pos*/) const { + CRITICAL_RAWRBOX("Not implemented"); + } + + rawrbox::Vector3f CameraBase::screenToWorld(const rawrbox::Vector2f& /*screen_pos*/, const rawrbox::Vector3f& /*origin*/) const { + CRITICAL_RAWRBOX("Not implemented"); + } + + bool CameraBase::isEnabled() const { return this->_enabled; } + void CameraBase::setEnabled(bool enabled) { this->_enabled = enabled; } + + uint32_t CameraBase::getLayers() const { return this->_layers; } + void CameraBase::setLayers(uint32_t layers) { this->_layers = layers; } + bool CameraBase::shouldRenderLayer(uint32_t layer) const { return (this->_layers & layer) > 1; } + // ----------- + + // RENDER TARGET ---- + void CameraBase::begin() { + if (this->_renderTarget == nullptr) CRITICAL_RAWRBOX("Render target not initialized!"); + this->_renderTarget->startRecord(); + } + + void CameraBase::end() { + if (this->_renderTarget == nullptr) CRITICAL_RAWRBOX("Render target not initialized!"); + this->_renderTarget->stopRecord(); + } + + Diligent::ITextureView* CameraBase::getDepth() const { return this->_renderTarget->getDepth(); } + Diligent::ITextureView* CameraBase::getColor(bool rt) const { return rt ? this->_renderTarget->getRT() : this->_renderTarget->getHandle(); } + + rawrbox::TextureRender* CameraBase::getRenderTarget() const { return this->_renderTarget.get(); } + // ---------------- + void CameraBase::updateBuffer() { - if (this->_uniforms == nullptr) CRITICAL_RAWRBOX("Buffer not initialized! Did you call initialize?"); + if (uniforms == nullptr) CRITICAL_RAWRBOX("Buffer not initialized! Did you call initialize?"); auto view = rawrbox::Matrix4x4::mtxTranspose(this->getViewMtx()); auto viewInv = rawrbox::Matrix4x4::mtxInverse(this->getViewMtx()); @@ -150,22 +203,12 @@ namespace rawrbox { data.gPos = this->getPos(); data.gDeltaTime = rawrbox::DELTA_TIME; - rawrbox::BarrierUtils::barrier({{this->_uniforms, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::RESOURCE_STATE_COPY_DEST, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}}); - rawrbox::RENDERER->context()->UpdateBuffer(this->_uniforms, 0, sizeof(rawrbox::CameraUniforms), &data, Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY); - rawrbox::BarrierUtils::barrier({{this->_uniforms, Diligent::RESOURCE_STATE_COPY_DEST, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}}); + rawrbox::BarrierUtils::barrier({{uniforms, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::RESOURCE_STATE_COPY_DEST, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}}); + rawrbox::RENDERER->context()->UpdateBuffer(uniforms, 0, sizeof(rawrbox::CameraUniforms), &data, Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY); + rawrbox::BarrierUtils::barrier({{uniforms, Diligent::RESOURCE_STATE_COPY_DEST, Diligent::RESOURCE_STATE_CONSTANT_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE}}); } void CameraBase::update() {} - - rawrbox::Vector3f CameraBase::worldToScreen(const rawrbox::Vector3f& /*pos*/) const { - CRITICAL_RAWRBOX("Not implemented"); - } - - rawrbox::Vector3f CameraBase::screenToWorld(const rawrbox::Vector2f& /*screen_pos*/, const rawrbox::Vector3f& /*origin*/) const { - CRITICAL_RAWRBOX("Not implemented"); - } - - Diligent::IBuffer* CameraBase::uniforms() const { return this->_uniforms; } - Diligent::IBuffer* CameraBase::staticUniforms() const { return this->_staticUniforms; } // ---------------- + } // namespace rawrbox diff --git a/rawrbox.render/src/cameras/perspective.cpp b/rawrbox.render/src/cameras/perspective.cpp index cd3bbe04..ca708dc5 100644 --- a/rawrbox.render/src/cameras/perspective.cpp +++ b/rawrbox.render/src/cameras/perspective.cpp @@ -4,11 +4,11 @@ namespace rawrbox { // NOLINTBEGIN(clang-analyzer-optin.cplusplus.VirtualCall) - CameraPerspective::CameraPerspective(const rawrbox::Vector2u& winSize, float FOV, float near, float far) : _winSize(winSize), _FOV(FOV) { + CameraPerspective::CameraPerspective(const rawrbox::Vector2u& renderSize, float FOV, float near, float far, bool depth) : rawrbox::CameraBase(renderSize, depth), _FOV(FOV) { this->_z_near = near; this->_z_far = far; - this->_projection = rawrbox::Matrix4x4::mtxProj(FOV, static_cast(winSize.x) / static_cast(winSize.y), this->_z_near, this->_z_far); + this->_projection = rawrbox::Matrix4x4::mtxProj(FOV, static_cast(renderSize.x) / static_cast(renderSize.y), this->_z_near, this->_z_far); this->updateMtx(); } // NOLINTEND(clang-analyzer-optin.cplusplus.VirtualCall) @@ -23,18 +23,19 @@ namespace rawrbox { } rawrbox::Vector3f CameraPerspective::worldToScreen(const rawrbox::Vector3f& pos) const { - return rawrbox::Matrix4x4::mtxProject(pos, this->_view, this->_projection, {0, 0, this->_winSize.x, this->_winSize.y}); + const auto& size = this->_renderTarget->getSize(); + return rawrbox::Matrix4x4::mtxProject(pos, this->_view, this->_projection, {0, 0, size.x, size.y}); } rawrbox::Vector3f CameraPerspective::screenToWorld(const rawrbox::Vector2f& screenPos, const rawrbox::Vector3f& origin) const { - rawrbox::Vector3f plane_normal = {0, 1, 0}; + static constexpr rawrbox::Vector3f plane_normal = {0, 1, 0}; // get our pos and force aim downwards, the getForward() seems to behave odd when aiming full down - auto campos = this->getPos(); + const auto& campos = this->getPos(); + const auto& size = this->_renderTarget->getSize(); rawrbox::Matrix4x4 viewproj_inv = this->getViewProjMtx().inverse(); - auto winPos = this->_winSize.cast(); - + auto winPos = size.cast(); float screenx_clip = 2.F * (screenPos.x / winPos.x) - 1.F; float screeny_clip = 1.F - 2.F * (screenPos.y) / winPos.y; diff --git a/rawrbox.render/src/plugins/base.cpp b/rawrbox.render/src/plugins/base.cpp index fb48831f..3983b5dd 100644 --- a/rawrbox.render/src/plugins/base.cpp +++ b/rawrbox.render/src/plugins/base.cpp @@ -17,8 +17,8 @@ namespace rawrbox { void RenderPlugin::resize(const rawrbox::Vector2u& /*renderSize*/) {} void RenderPlugin::upload() {} - void RenderPlugin::preRender() {} - void RenderPlugin::postRender(rawrbox::TextureRender& /*renderTarget*/) {} + void RenderPlugin::preRender(const rawrbox::CameraBase& /*camera*/) {} + void RenderPlugin::postRender(const rawrbox::CameraBase& /*camera*/) {} void RenderPlugin::update() {} } // namespace rawrbox diff --git a/rawrbox.render/src/plugins/clustered.cpp b/rawrbox.render/src/plugins/clustered.cpp index a17c83b1..1168f58c 100644 --- a/rawrbox.render/src/plugins/clustered.cpp +++ b/rawrbox.render/src/plugins/clustered.cpp @@ -61,11 +61,31 @@ namespace rawrbox { this->_dispatch.ThreadGroupCountY = rawrbox::MathUtils::divideRound(CLUSTERS_Y, RB_RENDER_CLUSTERS_Y_THREADS); // ---------- + // Re-build clusters --- + this->_oldProj = {}; // -------------------------- - this->_oldProj = {}; // Re-build clusters } void ClusteredPlugin::upload() { + if (this->_signature == nullptr) CRITICAL_RAWRBOX("Signature not initialized, did you call 'initialize'?"); + if (rawrbox::MAIN_CAMERA == nullptr) CRITICAL_RAWRBOX("Main camera not initialized"); + + // Compute bind --- + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Camera")->Set(rawrbox::CameraBase::uniforms); + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "SCamera")->Set(rawrbox::CameraBase::staticUniforms); + + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Clusters")->Set(this->getClustersBuffer(false)); + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "ClusterDataGrid")->Set(this->getDataGridBuffer(false)); + + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Lights")->Set(rawrbox::LIGHTS::getBuffer()); + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "LightConstants")->Set(rawrbox::LIGHTS::uniforms); + + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Decals")->Set(rawrbox::DECALS::getBuffer()); + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "DecalsConstants")->Set(rawrbox::DECALS::uniforms); + + this->_signature->CreateShaderResourceBinding(&this->_signatureBind, true); + // ---------------- + this->buildPipelines(); } @@ -91,13 +111,12 @@ namespace rawrbox { sig.GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "DecalsConstants")->Set(rawrbox::DECALS::uniforms); } - void ClusteredPlugin::preRender() { + void ClusteredPlugin::preRender(const rawrbox::CameraBase& camera) { auto* renderer = rawrbox::RENDERER; - auto* camera = renderer->camera(); - auto* context = renderer->context(); - if (renderer == nullptr) CRITICAL_RAWRBOX("Renderer not initialized!"); - if (camera == nullptr) CRITICAL_RAWRBOX("Camera not initialized!"); + + auto* context = renderer->context(); + if (context == nullptr) CRITICAL_RAWRBOX("Context not initialized!"); if (this->_clusterBuildingComputeProgram == nullptr || this->_cullingComputeProgram == nullptr || this->_cullingResetProgram == nullptr) CRITICAL_RAWRBOX("Compute pipelines not initialized, did you call 'initialize'"); @@ -118,7 +137,7 @@ namespace rawrbox { // ----------------------- // Rebuild clusters --- - auto proj = camera->getProjMtx(); + auto proj = camera.getProjMtx(); if (this->_oldProj != proj) { this->_oldProj = proj; @@ -194,7 +213,6 @@ namespace rawrbox { void ClusteredPlugin::buildSignatures() { if (this->_signature != nullptr || this->_signatureBind != nullptr) CRITICAL_RAWRBOX("Signatures already bound!"); - if (rawrbox::MAIN_CAMERA == nullptr) CRITICAL_RAWRBOX("Clustered plugin requires at least one camera!"); std::vector resources = { // CAMERA ------ @@ -231,26 +249,10 @@ namespace rawrbox { rawrbox::RENDERER->device()->CreatePipelineResourceSignature(PRSDesc, &this->_signature); // ---------------------- - - // Compute bind --- - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Camera")->Set(rawrbox::MAIN_CAMERA->uniforms()); - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "SCamera")->Set(rawrbox::MAIN_CAMERA->staticUniforms()); - - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Clusters")->Set(this->getClustersBuffer(false)); - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "ClusterDataGrid")->Set(this->getDataGridBuffer(false)); - - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Lights")->Set(rawrbox::LIGHTS::getBuffer()); - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "LightConstants")->Set(rawrbox::LIGHTS::uniforms); - - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Decals")->Set(rawrbox::DECALS::getBuffer()); - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "DecalsConstants")->Set(rawrbox::DECALS::uniforms); - - this->_signature->CreateShaderResourceBinding(&this->_signatureBind, true); - // ---------------- } void ClusteredPlugin::buildPipelines() { - if (rawrbox::MAIN_CAMERA == nullptr) CRITICAL_RAWRBOX("Clustered plugin requires at least one camera!"); + if (this->_signature == nullptr) CRITICAL_RAWRBOX("Signature not initialized, did you call 'initialize'"); rawrbox::PipeComputeSettings settings; settings.macros = this->getClusterMacros(); diff --git a/rawrbox.render/src/plugins/particle_engine.cpp b/rawrbox.render/src/plugins/particle_engine.cpp index b0173462..b2d94610 100644 --- a/rawrbox.render/src/plugins/particle_engine.cpp +++ b/rawrbox.render/src/plugins/particle_engine.cpp @@ -45,15 +45,6 @@ namespace rawrbox { rawrbox::RENDERER->device()->CreatePipelineResourceSignature(PRSDesc, &this->_signature); // ---------------------- - // Compute bind --- - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Camera")->Set(rawrbox::MAIN_CAMERA->uniforms()); - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "SCamera")->Set(rawrbox::MAIN_CAMERA->staticUniforms()); - - this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "EmitterConstants")->Set(this->_uniforms); - - this->_signature->CreateShaderResourceBinding(&this->_signatureBind, true); - // ---------------- - // Dynamic signature --- PRSDesc.Name = "RawrBox::SIGNATURE::Particles::Dynamic"; PRSDesc.BindingIndex = 1; @@ -66,7 +57,6 @@ namespace rawrbox { PRSDesc.NumResources = static_cast(resources.size()); rawrbox::RENDERER->device()->CreatePipelineResourceSignature(PRSDesc, &this->_dynamicSignature); - this->_dynamicSignature->CreateShaderResourceBinding(&this->_dynamicSignatureBind, true); // ---------------- } @@ -98,6 +88,18 @@ namespace rawrbox { } void ParticleEnginePlugin::upload() { + if (this->_signature == nullptr || this->_signatureBind == nullptr || this->_uniforms == nullptr) CRITICAL_RAWRBOX("Plugin not initialized!"); + + // Compute bind --- + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "Camera")->Set(rawrbox::CameraBase::uniforms); + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "SCamera")->Set(rawrbox::CameraBase::staticUniforms); + + this->_signature->GetStaticVariableByName(Diligent::SHADER_TYPE_COMPUTE, "EmitterConstants")->Set(this->_uniforms); + + this->_signature->CreateShaderResourceBinding(&this->_signatureBind, true); + this->_dynamicSignature->CreateShaderResourceBinding(&this->_dynamicSignatureBind, true); + // ---------------- + this->createPipelines(); } @@ -109,7 +111,7 @@ namespace rawrbox { sig.GetStaticVariableByName(Diligent::SHADER_TYPE_GEOMETRY, "EmitterConstants")->Set(this->_uniforms); } - void ParticleEnginePlugin::preRender() { + void ParticleEnginePlugin::preRender(const rawrbox::CameraBase& /*camera*/) { for (auto* emitter : this->_registeredEmitters) { if (emitter == nullptr || !emitter->isEnabled()) continue; diff --git a/rawrbox.render/src/plugins/post_process.cpp b/rawrbox.render/src/plugins/post_process.cpp index 7b7e349a..df5811f9 100644 --- a/rawrbox.render/src/plugins/post_process.cpp +++ b/rawrbox.render/src/plugins/post_process.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace rawrbox { PostProcessPlugin::~PostProcessPlugin() { @@ -8,6 +9,8 @@ namespace rawrbox { } void PostProcessPlugin::initialize(const rawrbox::Vector2u& /*size*/) { + if (this->_buffer != nullptr) CRITICAL_RAWRBOX("Plugin already initialized!"); + Diligent::BufferDesc BuffPixelDesc; BuffPixelDesc.Name = "rawrbox::PostProcess"; BuffPixelDesc.Usage = Diligent::USAGE_DYNAMIC; @@ -23,8 +26,8 @@ namespace rawrbox { } void PostProcessPlugin::upload() { - for (const auto& _postProcess : this->_postProcesses) { - _postProcess->init(); + for (const auto& postProcess : this->_postProcesses) { + postProcess->init(); } } @@ -36,14 +39,20 @@ namespace rawrbox { sig.GetStaticVariableByName(Diligent::SHADER_TYPE_PIXEL, "PostProcessConstants")->Set(this->_buffer); } - void PostProcessPlugin::postRender(rawrbox::TextureRender& renderTexture) { + void PostProcessPlugin::postRender(const rawrbox::CameraBase& camera) { + if (&camera != rawrbox::MAIN_CAMERA) return; // Only apply on the main camera + + auto* renderTarget = camera.getRenderTarget(); + + // Apply post-processing --- for (auto& process : this->_postProcesses) { if (!process->isEnabled()) continue; - renderTexture.startRecord(false, 1); - process->applyEffect(renderTexture); - renderTexture.stopRecord(); + renderTarget->startRecord(false, 1); + process->applyEffect(*renderTarget); + renderTarget->stopRecord(); } + // ---------- } // Post utils ---- diff --git a/rawrbox.render/src/renderer.cpp b/rawrbox.render/src/renderer.cpp index c9bf3c9a..e755ef04 100644 --- a/rawrbox.render/src/renderer.cpp +++ b/rawrbox.render/src/renderer.cpp @@ -41,7 +41,6 @@ namespace rawrbox { RendererBase::RendererBase(Diligent::RENDER_DEVICE_TYPE type, Diligent::NativeWindow window, const rawrbox::Vector2u& size, const rawrbox::Vector2u& monitorSize, const rawrbox::Colorf& clearColor) : _clearColor(clearColor), _size(size), _monitorSize(monitorSize), _window(window), _type(type) {} RendererBase::~RendererBase() { - this->_render.reset(); this->_stencil.reset(); this->_logger.reset(); this->_GPUBlit.reset(); @@ -241,11 +240,6 @@ namespace rawrbox { // -------------- // ---------------------- - // Setup camera ----- - if (this->_camera == nullptr) CRITICAL_RAWRBOX("No camera found!"); - this->_camera->initialize(); - // ------------------ - // Init plugins --- for (auto& plugin : this->_renderPlugins) { if (plugin.second == nullptr) continue; @@ -258,6 +252,19 @@ namespace rawrbox { rawrbox::BindlessManager::init(); // ----------------- + // Init cameras --- + this->setActiveCamera(this->_cameras.front().get()); + for (auto& camera : this->_cameras) { + camera->initialize(); + } + + rawrbox::MAIN_CAMERA->upload(); + // ----------------- + + // Bind signatures --- + rawrbox::BindlessManager::bindSignatures(); + // ------- + // Init default textures --- this->_logger->info("Initializing default textures"); @@ -335,15 +342,6 @@ namespace rawrbox { this->_stencil->upload(); // ------------------ - // Setup renderer -- - this->_render = std::make_unique(this->_size); // TODO: RESCALE - this->_render->upload(Diligent::TEX_FORMAT_RGBA8_UNORM); - - // GPU PICKING TEXTURE - auto idIndex = this->_render->addTexture(Diligent::TEX_FORMAT_RGBA8_UNORM); - this->_render->addView(idIndex, Diligent::TEXTURE_VIEW_RENDER_TARGET); - // -------- - this->playIntro(); this->_initialized = true; } @@ -370,7 +368,7 @@ namespace rawrbox { const std::map>& RendererBase::getPlugins() const { return this->_renderPlugins; } // ----------------------------------- - void RendererBase::setDrawCall(std::function call) { this->_drawCall = std::move(call); } + void RendererBase::setDrawCall(std::function call) { this->_drawCall = std::move(call); } void RendererBase::update() { if (this->_currentIntro != nullptr) { @@ -389,7 +387,12 @@ namespace rawrbox { return; } } else { - if (this->_camera != nullptr) this->_camera->update(); + // Update cameras --- + for (auto& camera : this->_cameras) { + if (!camera->isEnabled()) continue; + camera->update(); + } + // ----------------------- // Update plugins -- for (auto& plugin : this->_renderPlugins) { @@ -403,6 +406,7 @@ namespace rawrbox { void RendererBase::render() { if (this->_swapChain == nullptr || this->_context == nullptr || this->_device == nullptr) CRITICAL_RAWRBOX("Failed to bind swapChain / context / device! Did you call 'init' ?"); if (this->_drawCall == nullptr) CRITICAL_RAWRBOX("Missing draw call! Did you call 'setDrawCall' ?"); + if (rawrbox::MAIN_CAMERA == nullptr || this->_cameras.empty()) CRITICAL_RAWRBOX("Missing cameras! Did you call 'createCamera' ?"); // Clear backbuffer ---- this->clear(); @@ -412,70 +416,46 @@ namespace rawrbox { rawrbox::BindlessManager::update(); // -------------------- - // Update camera buffer -- - this->_camera->updateBuffer(); - // ----------- + for (auto& camera : this->_cameras) { + if (!camera->isEnabled()) continue; - // Perform pre-render -- - for (auto& plugin : this->_renderPlugins) { - if (plugin.second == nullptr || !plugin.second->isEnabled()) continue; -#ifdef _DEBUG - // this->_context->BeginDebugGroup(plugin.first.c_str()); -#endif - plugin.second->preRender(); -#ifdef _DEBUG - // this->_context->EndDebugGroup(); -#endif - } - // ----------------------- + // Update camera buffer -- + camera->updateBuffer(); + // ----------- - // Commit graphics signature -- - this->_context->CommitShaderResources(rawrbox::BindlessManager::signatureBind, Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY); - // ----------------------- + // Perform pre-render -- + for (auto& plugin : this->_renderPlugins) { + if (plugin.second == nullptr || !plugin.second->isEnabled()) continue; + plugin.second->preRender(*camera); + } + // ----------------------- - // Perform world -- -#ifdef _DEBUG - // this->_context->BeginDebugGroup("OPAQUE"); - // this->beginQuery("OPAQUE"); -#endif - this->_render->startRecord(); - this->_drawCall(rawrbox::DrawPass::PASS_WORLD); - this->_render->stopRecord(); -#ifdef _DEBUG - // this->endQuery("OPAQUE"); - // this->_context->EndDebugGroup(); -#endif - // ----------------- + // Commit graphics signature -- + this->_context->CommitShaderResources(rawrbox::BindlessManager::signatureBind, Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY); + // ----------------------- - // Perform post-render -- - for (auto& plugin : this->_renderPlugins) { - if (plugin.second == nullptr || !plugin.second->isEnabled()) continue; -#ifdef _DEBUG - // this->_context->BeginDebugGroup(plugin.first.c_str()); -#endif - plugin.second->postRender(*this->_render); -#ifdef _DEBUG - // this->_context->EndDebugGroup(); -#endif + // Perform world -- + camera->begin(); + this->_drawCall(*camera, rawrbox::DrawPass::PASS_WORLD); + camera->end(); + // ----------------- + + // Perform post-render -- + for (auto& plugin : this->_renderPlugins) { + if (plugin.second == nullptr || !plugin.second->isEnabled()) continue; + plugin.second->postRender(*camera); + } + // ----------------------- } - // ----------------------- - // Render world ---- - rawrbox::RenderUtils::renderQUAD(*this->_render); + // Render main camera ---- + rawrbox::RenderUtils::renderQUAD(*rawrbox::MAIN_CAMERA->getRenderTarget()); // ------------------ - // Perform overlay -- -#ifdef _DEBUG - // this->_context->BeginDebugGroup("OVERLAY"); - // this->beginQuery("OVERLAY"); -#endif - this->_drawCall(rawrbox::DrawPass::PASS_OVERLAY); + // Perform overlay, only MAIN camera does it -- + this->_drawCall(*rawrbox::MAIN_CAMERA, rawrbox::DrawPass::PASS_OVERLAY); if (this->_stencil != nullptr) this->_stencil->render(); -#ifdef _DEBUG - // this->endQuery("OVERLAY"); - // this->_context->EndDebugGroup(); -#endif - // ------------------ + // --------------------------------------------- // Submit --- this->frame(); @@ -522,7 +502,7 @@ namespace rawrbox { this->_tempRender = this->_drawCall; // ------------- - this->_drawCall = [this](const rawrbox::DrawPass& pass) { + this->_drawCall = [this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_OVERLAY) return; auto screenSize = this->_size.cast(); @@ -668,22 +648,15 @@ namespace rawrbox { // ---------------- // Utils ---- - void RendererBase::setMainCamera(rawrbox::CameraBase* camera) const { rawrbox::MAIN_CAMERA = camera; } - rawrbox::CameraBase* RendererBase::camera() const { return this->_camera.get(); } + void RendererBase::setActiveCamera(rawrbox::CameraBase* camera) const { rawrbox::MAIN_CAMERA = camera; } + rawrbox::CameraBase* RendererBase::getActiveCamera() const { return rawrbox::MAIN_CAMERA; } + rawrbox::Stencil* RendererBase::stencil() const { return this->_stencil.get(); } Diligent::IDeviceContext* RendererBase::context() const { return this->_context; } Diligent::ISwapChain* RendererBase::swapChain() const { return this->_swapChain; } Diligent::IRenderDevice* RendererBase::device() const { return this->_device; } - Diligent::ITextureView* RendererBase::getDepth() const { - return this->_render->getDepth(); - } - - Diligent::ITextureView* RendererBase::getColor(bool rt) const { - return rt ? this->_render->getRT() : this->_render->getHandle(); - } - std::filesystem::path RendererBase::getShadersDirectory() const { return "./assets/shaders"; } @@ -711,8 +684,8 @@ namespace rawrbox { void RendererBase::setVSync(bool vsync) { this->_vsync = vsync; } void RendererBase::gpuPick(const rawrbox::Vector2i& pos, const std::function& callback) { - if (this->_render == nullptr) CRITICAL_RAWRBOX("Render target texture not initialized"); - if (callback == nullptr) CRITICAL_RAWRBOX("Render target texture not initialized"); + if (rawrbox::MAIN_CAMERA == nullptr) CRITICAL_RAWRBOX("Main camera not initialized"); + if (callback == nullptr) CRITICAL_RAWRBOX("Invalid callback"); auto size = this->_size.cast(); if (pos.x < 0 || pos.y < 0 || pos.x >= size.x || pos.y >= size.y) CRITICAL_RAWRBOX("Outside of window range"); @@ -723,7 +696,7 @@ namespace rawrbox { MapRegion.MaxX = MapRegion.MinX + RB_RENDER_GPU_PICK_SAMPLE_SIZE; MapRegion.MaxY = MapRegion.MinY + RB_RENDER_GPU_PICK_SAMPLE_SIZE; - auto* tex = this->_render->getTexture(1); // GPU pick texture + auto* tex = rawrbox::MAIN_CAMERA->getRenderTarget()->getTexture(1); // GPU pick texture this->_GPUBlit->copy(tex, &MapRegion, [this, callback]() { this->_GPUBlit->blit(nullptr, [callback](const uint8_t* pixels, const uint64_t stride) { uint32_t max = 0; diff --git a/samples/001-stencil/src/game.cpp b/samples/001-stencil/src/game.cpp index 12a37775..be9750eb 100644 --- a/samples/001-stencil/src/game.cpp +++ b/samples/001-stencil/src/game.cpp @@ -38,7 +38,7 @@ namespace stencil { // Setup renderer auto* render = window->createRenderer(rawrbox::Color::RGBAHex(0x443355FF)); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_OVERLAY) { this->drawOverlay(); } else if (pass == rawrbox::DrawPass::PASS_WORLD) { @@ -48,7 +48,7 @@ namespace stencil { // --------------- // Setup camera -- - auto* cam = render->setupCamera(render->getSize()); + auto* cam = render->createCamera(render->getSize()); cam->setPos({-2.F, 5.F, -3.5F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // --------------- diff --git a/samples/002-generated-models/include/model/game.hpp b/samples/002-generated-models/include/model/game.hpp index 2ef9c512..b8453193 100644 --- a/samples/002-generated-models/include/model/game.hpp +++ b/samples/002-generated-models/include/model/game.hpp @@ -21,12 +21,14 @@ namespace model { bool _ready = false; bool _bbox = true; + // Engine setup --- void setupGLFW() override; void init() override; void onThreadShutdown(rawrbox::ENGINE_THREADS thread) override; void pollEvents() override; void update() override; void draw() override; + // ---------------- void createModels(); void createSpline(); diff --git a/samples/002-generated-models/src/game.cpp b/samples/002-generated-models/src/game.cpp index 06a2bfce..97e5277e 100644 --- a/samples/002-generated-models/src/game.cpp +++ b/samples/002-generated-models/src/game.cpp @@ -35,7 +35,7 @@ namespace model { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -45,7 +45,7 @@ namespace model { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 6.F, -6.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-55), 0.F, 0.F}); cam->onMovementStart = []() { fmt::print("Camera start\n"); }; diff --git a/samples/003-light/src/game.cpp b/samples/003-light/src/game.cpp index b07da3fb..506e73f1 100644 --- a/samples/003-light/src/game.cpp +++ b/samples/003-light/src/game.cpp @@ -38,7 +38,7 @@ namespace light { auto* render = window->createRenderer(); render->addPlugin(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -48,7 +48,7 @@ namespace light { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/004-instancing/src/game.cpp b/samples/004-instancing/src/game.cpp index dc1c2d29..4f41b074 100644 --- a/samples/004-instancing/src/game.cpp +++ b/samples/004-instancing/src/game.cpp @@ -39,14 +39,14 @@ namespace instance_test { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_WORLD) return; this->drawWorld(); }); // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/005-post-process/src/game.cpp b/samples/005-post-process/src/game.cpp index a864bed9..b0582516 100644 --- a/samples/005-post-process/src/game.cpp +++ b/samples/005-post-process/src/game.cpp @@ -48,7 +48,7 @@ namespace post_process { this->_noise = postProcess->add(0.1F); // ----------------------- - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -61,7 +61,7 @@ namespace post_process { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/006-decals/src/game.cpp b/samples/006-decals/src/game.cpp index 66a8c760..93a2070d 100644 --- a/samples/006-decals/src/game.cpp +++ b/samples/006-decals/src/game.cpp @@ -41,7 +41,7 @@ namespace decal_test { auto* render = window->createRenderer(); render->addPlugin(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -51,7 +51,7 @@ namespace decal_test { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/007-particle-system/src/game.cpp b/samples/007-particle-system/src/game.cpp index 83065e84..bef48691 100644 --- a/samples/007-particle-system/src/game.cpp +++ b/samples/007-particle-system/src/game.cpp @@ -35,14 +35,14 @@ namespace particle_system { auto* render = window->createRenderer(); render->addPlugin(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_WORLD) return; this->drawWorld(); }); // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/008-ui/src/game.cpp b/samples/008-ui/src/game.cpp index 784207c9..e28350e9 100644 --- a/samples/008-ui/src/game.cpp +++ b/samples/008-ui/src/game.cpp @@ -50,14 +50,14 @@ namespace ui_test { // Setup renderer auto* render = window->createRenderer(rawrbox::Color::RGBAHex(0x443355FF)); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_OVERLAY) return; this->_ROOT_UI->render(); }); // --------------- // Setup camera -- - auto* cam = render->setupCamera(render->getSize()); + auto* cam = render->createCamera(render->getSize()); cam->setPos({-2.F, 5.F, -3.5F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // --------------- diff --git a/samples/009-gltf/src/game.cpp b/samples/009-gltf/src/game.cpp index 1d3b70cd..68bb81d6 100644 --- a/samples/009-gltf/src/game.cpp +++ b/samples/009-gltf/src/game.cpp @@ -36,14 +36,14 @@ namespace gltf { auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; render->addPlugin(); - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_WORLD) return; this->drawWorld(); }); // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/010-bass-audio/src/game.cpp b/samples/010-bass-audio/src/game.cpp index 1fb6e03c..fa20f8c3 100644 --- a/samples/010-bass-audio/src/game.cpp +++ b/samples/010-bass-audio/src/game.cpp @@ -34,14 +34,14 @@ namespace bass_test { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_WORLD) return; this->drawWorld(); }); // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/011-physics-3D/src/game.cpp b/samples/011-physics-3D/src/game.cpp index b1bc7750..28fbd2d0 100644 --- a/samples/011-physics-3D/src/game.cpp +++ b/samples/011-physics-3D/src/game.cpp @@ -34,7 +34,7 @@ namespace phys_3d_test { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -44,7 +44,7 @@ namespace phys_3d_test { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/012-physics-2D/src/game.cpp b/samples/012-physics-2D/src/game.cpp index efa96727..6fcd661b 100644 --- a/samples/012-physics-2D/src/game.cpp +++ b/samples/012-physics-2D/src/game.cpp @@ -35,7 +35,7 @@ namespace phys_2d_test { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -45,7 +45,7 @@ namespace phys_2d_test { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, 0.F, 0.F, 0.F}); // -------------- diff --git a/samples/013-webm/src/game.cpp b/samples/013-webm/src/game.cpp index 70df5a7c..5841b3a6 100644 --- a/samples/013-webm/src/game.cpp +++ b/samples/013-webm/src/game.cpp @@ -35,14 +35,14 @@ namespace webm_test { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_WORLD) return; this->drawWorld(); }); // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -10.F}); cam->setAngle({0.F, 0.F, 0.F, 0.F}); // -------------- diff --git a/samples/014-scripting/src/game.cpp b/samples/014-scripting/src/game.cpp index c47c87e9..e3115726 100644 --- a/samples/014-scripting/src/game.cpp +++ b/samples/014-scripting/src/game.cpp @@ -51,7 +51,7 @@ namespace scripting_test { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_WORLD) { this->drawWorld(); } else { @@ -61,7 +61,7 @@ namespace scripting_test { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/015-gpu-picking/src/game.cpp b/samples/015-gpu-picking/src/game.cpp index 589b2060..c29c70a1 100644 --- a/samples/015-gpu-picking/src/game.cpp +++ b/samples/015-gpu-picking/src/game.cpp @@ -31,14 +31,14 @@ namespace gpu { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_WORLD) return; this->drawWorld(); }); // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/016-steamworks/src/game.cpp b/samples/016-steamworks/src/game.cpp index c254aca7..73f12856 100644 --- a/samples/016-steamworks/src/game.cpp +++ b/samples/016-steamworks/src/game.cpp @@ -33,7 +33,7 @@ namespace steamworks { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass == rawrbox::DrawPass::PASS_OVERLAY) { this->drawOverlay(); } else { @@ -43,7 +43,7 @@ namespace steamworks { // --------------- // Setup camera - auto* cam = render->setupCamera(*window); + auto* cam = render->createCamera(*window); cam->setPos({0.F, 5.F, -5.F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // -------------- diff --git a/samples/017-imgui/src/game.cpp b/samples/017-imgui/src/game.cpp index 83de2d45..a4f61928 100644 --- a/samples/017-imgui/src/game.cpp +++ b/samples/017-imgui/src/game.cpp @@ -34,14 +34,14 @@ namespace imgui { // Setup renderer auto* render = window->createRenderer(); render->onIntroCompleted = [this]() { this->loadContent(); }; - render->setDrawCall([this](const rawrbox::DrawPass& pass) { + render->setDrawCall([this](const rawrbox::CameraBase& /*camera*/, const rawrbox::DrawPass& pass) { if (pass != rawrbox::DrawPass::PASS_OVERLAY) return; this->drawOverlay(); }); // --------------- // Setup camera -- - auto* cam = render->setupCamera(render->getSize()); + auto* cam = render->createCamera(render->getSize()); cam->setPos({-2.F, 5.F, -3.5F}); cam->setAngle({0.F, rawrbox::MathUtils::toRad(-45), 0.F, 0.F}); // --------------- @@ -82,6 +82,10 @@ namespace imgui { } void Game::onThreadShutdown(rawrbox::ENGINE_THREADS thread) { + if (thread == rawrbox::ENGINE_THREADS::THREAD_RENDER) { + rawrbox::RESOURCES::shutdown(); + } + rawrbox::IMGUIManager::shutdown(thread); rawrbox::Window::shutdown(thread); } diff --git a/samples/018-camera/CMakeLists.txt b/samples/018-camera/CMakeLists.txt new file mode 100644 index 00000000..5c7df8bb --- /dev/null +++ b/samples/018-camera/CMakeLists.txt @@ -0,0 +1,23 @@ +set(output_target 018-camera) +project(${output_target}) +# -------------- + +# Grab source files +file(GLOB_RECURSE RAWRBOX_SAMPLE_SOURCES "include/*.hpp" "src/*.cpp") + +# Project setup +add_executable(${output_target} ${RAWRBOX_SAMPLE_SOURCES}) +add_dependencies(${output_target} copy_resources_samples) +target_include_directories(${output_target} PRIVATE "include") +target_compile_features(${output_target} PRIVATE cxx_std_${CMAKE_CXX_STANDARD}) +target_link_libraries(${output_target} PRIVATE RAWRBOX.RENDER) +target_compile_definitions(${output_target} PRIVATE NOMINMAX) + +set_lib_runtime_mt(${output_target}) + +if(NOT WIN32) + set_target_properties(${output_target} PROPERTIES LINK_FLAGS -Wl,-rpath,'\$ORIGIN') +else() + + copy_required_dlls(${output_target}) # Required by diligent +endif() diff --git a/samples/018-camera/README.md b/samples/018-camera/README.md new file mode 100644 index 00000000..fb7d5573 --- /dev/null +++ b/samples/018-camera/README.md @@ -0,0 +1,6 @@ +# 018-camera Sample + +> [!NOTE] +> This sample demonstrates how to integrate multiple cameras and layer filtering + +![](https://i.rawr.dev/sample18-min.gif) diff --git a/samples/018-camera/include/camera/game.hpp b/samples/018-camera/include/camera/game.hpp new file mode 100644 index 00000000..141f3a95 --- /dev/null +++ b/samples/018-camera/include/camera/game.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace camera { + class Game : public rawrbox::Engine { + std::unique_ptr> _model = std::make_unique>(); + std::unique_ptr> _model2 = std::make_unique>(); + std::unique_ptr> _bboxes = std::make_unique>(); + std::unique_ptr> _text = std::make_unique>(); + + rawrbox::CameraPerspective* _camera = nullptr; + + bool _ready = false; + bool _layers = true; + + // Engine setup --- + void setupGLFW() override; + void init() override; + void onThreadShutdown(rawrbox::ENGINE_THREADS thread) override; + void pollEvents() override; + void update() override; + void draw() override; + // ---------------- + + public: + Game() = default; + Game(const Game&) = delete; + Game(Game&&) = delete; + Game& operator=(const Game&) = delete; + Game& operator=(Game&&) = delete; + ~Game() override = default; + + void drawWorld(uint32_t layer); + void drawOverlay(); + + void loadContent(); + void contentLoaded(); + }; +} // namespace camera diff --git a/samples/018-camera/src/game.cpp b/samples/018-camera/src/game.cpp new file mode 100644 index 00000000..ad9ff821 --- /dev/null +++ b/samples/018-camera/src/game.cpp @@ -0,0 +1,178 @@ + +#include +#include +#include +#include +#include + +#include + +#include + +namespace camera { + void Game::setupGLFW() { +#if defined(_DEBUG) && defined(RAWRBOX_SUPPORT_DX12) + auto* window = rawrbox::Window::createWindow(Diligent::RENDER_DEVICE_TYPE_D3D12); // DX12 is faster on DEBUG than Vulkan, due to vulkan having extra check steps to prevent you from doing bad things +#else + auto* window = rawrbox::Window::createWindow(); +#endif + window->setMonitor(-1); + window->setTitle("CAMERA TEST"); +#ifdef _DEBUG + window->init(1600, 900, rawrbox::WindowFlags::Window::WINDOWED); +#else + window->init(0, 0, rawrbox::WindowFlags::Window::BORDERLESS); +#endif + + window->onWindowClose += [this](auto& /*w*/) { this->shutdown(); }; + } + + void Game::init() { + auto* window = rawrbox::Window::getWindow(); + + // Setup renderer + auto* render = window->createRenderer(); + render->onIntroCompleted = [this]() { this->loadContent(); }; + render->setDrawCall([this](const rawrbox::CameraBase& camera, const rawrbox::DrawPass& pass) { + if (pass == rawrbox::DrawPass::PASS_OVERLAY) { + this->drawOverlay(); + } else { + this->drawWorld(camera.getLayers()); + } + }); + // --------------- + + // Setup main camera + auto* cam = render->createCamera(*window); + cam->setPos({0.F, 6.F, -6.F}); + cam->setAngle({0.F, rawrbox::MathUtils::toRad(-55), 0.F, 0.F}); + // -------------- + + // Setup camera 2 + this->_camera = render->createCamera(rawrbox::Vector2u{256, 256}); + this->_camera->setPos({0.F, 6.F, -6.F}); + this->_camera->setAngle({0.F, rawrbox::MathUtils::toRad(-55), 0.F, 0.F}); + this->_camera->setLayers(rawrbox::CameraLayers::LAYER_1); // Only draw objects on layer 1 (the name can be changed on the render_config.hpp file) + // -------------- + + // Add loaders + rawrbox::RESOURCES::addLoader(); + // -------------- + + // BINDS ---- + window->onKey += [this](rawrbox::Window& /*w*/, uint32_t key, uint32_t /*scancode*/, uint32_t action, uint32_t /*mods*/) { + if (!this->_ready || action != rawrbox::KEY_ACTION_UP || key != rawrbox::KEY_F1) return; + this->_layers = !this->_layers; + }; + // ----- + + render->init(); + } + + void Game::loadContent() { + std::vector> initialContentFiles = { + {"./assets/textures/fire1.gif", 0}, + {"./assets/textures/screem.png", 0}, + }; + + rawrbox::RESOURCES::loadListAsync(initialContentFiles, [this]() { + rawrbox::runOnRenderThread([this]() { + this->contentLoaded(); + }); + }); + } + + void Game::contentLoaded() { + if (this->_ready) return; + + auto* texture = rawrbox::RESOURCES::getFile("./assets/textures/fire1.gif")->get(); + auto* texture2 = rawrbox::RESOURCES::getFile("./assets/textures/screem.png")->get(); + + // SETUP MODELS --- + { + auto mesh = rawrbox::MeshUtils::generateCube({1.5F, 0, 0}, {1.0F, 1.0F, 1.0F}, rawrbox::Colors::White()); + mesh.setTexture(texture); + this->_model->addMesh(mesh); + this->_bboxes->addMesh(rawrbox::MeshUtils::generateBBOX({1.5F, 0, 0}, mesh.getBBOX())); + } + + { + auto mesh = rawrbox::MeshUtils::generatePlane({0, 0, 0}, {1.0F, 1.0F}, rawrbox::Colors::White()); + mesh.setTexture(this->_camera->getRenderTarget()); + this->_model->addMesh(mesh); + this->_bboxes->addMesh(rawrbox::MeshUtils::generateBBOX({0, 0, 0}, mesh.getBBOX())); + } + + { + auto mesh = rawrbox::MeshUtils::generateCube({-1.5F, 0, 0}, {1.0F, 1.0F, 1.0F}, rawrbox::Colors::White()); + mesh.setTexture(texture2); + this->_model2->addMesh(mesh); + this->_bboxes->addMesh(rawrbox::MeshUtils::generateBBOX({-1.5F, 0, 0}, mesh.getBBOX())); + } + // ---------------- + + // TEXT --- + this->_text->addText(*rawrbox::DEBUG_FONT_REGULAR, "ONLY VISIBLE IN CAMERA 2", {-1.5F, 1.2F, 0}); + this->_text->addText(*rawrbox::DEBUG_FONT_REGULAR, "CAMERA 2 RENDER TARGET", {0, 0.6F, 0}); + this->_text->addText(*rawrbox::DEBUG_FONT_REGULAR, "VISIBLE ON BOTH CAMERAS", {1.5F, 1.2F, 0}); + this->_text->upload(); + // -------- + + this->_model->upload(); + this->_model2->upload(); + this->_bboxes->upload(); + + this->_ready = true; + } + + void Game::onThreadShutdown(rawrbox::ENGINE_THREADS thread) { + if (thread == rawrbox::ENGINE_THREADS::THREAD_RENDER) { + this->_model.reset(); + this->_model2.reset(); + this->_bboxes.reset(); + this->_text.reset(); + + this->_camera = nullptr; + + rawrbox::RESOURCES::shutdown(); + } + + rawrbox::Window::shutdown(thread); + } + + void Game::pollEvents() { + rawrbox::Window::pollEvents(); + } + + void Game::update() { + rawrbox::Window::update(); + } + + void Game::drawWorld(uint32_t layer) { + if (!this->_ready) return; + + this->_model->draw(); + + if (this->_layers) { + if ((layer & rawrbox::CameraLayers::LAYER_1) > 0) { + this->_model2->draw(); + } + } else { + this->_model2->draw(); + } + + this->_bboxes->draw(); + this->_text->draw(); + } + + void Game::drawOverlay() { + if (!this->_ready) return; + auto* stencil = rawrbox::RENDERER->stencil(); + + stencil->drawText(fmt::format("[F1] LAYERS -> {}", this->_layers ? "enabled" : "disabled"), {15, 15}, rawrbox::Colors::White(), rawrbox::Colors::Black()); + } + + void Game::draw() { + rawrbox::Window::render(); // Commit primitives + } +} // namespace camera diff --git a/samples/018-camera/src/main.cpp b/samples/018-camera/src/main.cpp new file mode 100644 index 00000000..0a273b86 --- /dev/null +++ b/samples/018-camera/src/main.cpp @@ -0,0 +1,22 @@ + + +#ifdef _WIN32 + #include +#endif + +#include + +int main(int /*argc*/, char* /*argv*/[]) { +#ifdef _WIN32 + SetConsoleTitle("CAMERA TEST"); + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); +#endif + + camera::Game engine; + engine.setFPS(120); + engine.setTPS(66); + engine.run(); + + return 0; +} diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 1fcde53d..41b895a1 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -50,3 +50,5 @@ endif() if(RAWRBOX_BUILD_RAWRBOX_IMGUI) add_subdirectory("017-imgui") endif() + +add_subdirectory("018-camera")