From ad348b66c09bf1c3ef3ef69dfb9ed0a5e19db162 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 3 Sep 2025 22:44:22 +0100 Subject: [PATCH 01/11] Getting into the guts of drawing now. ironically removed pgeguts --- dev/msvc/olcPGE3.vcxproj | 14 ++-- dev/msvc/olcPGE3.vcxproj.filters | 3 + dev/src/core.cpp | 3 + dev/src/draw2d.cpp | 131 +++++++++++++++++++++++++++++++ dev/src/draw2d.h | 90 ++++++++++++++++----- dev/src/gpu_iface.h | 2 +- dev/src/gpu_opengl33.cpp | 2 +- dev/src/gpu_opengl33.h | 2 +- dev/src/gputask.h | 5 +- dev/src/image.cpp | 27 +++++++ dev/src/image.h | 17 ++-- dev/src/window.cpp | 4 + dev/src/window.h | 5 ++ dev/tests/test_mh.cpp | 2 + 14 files changed, 270 insertions(+), 37 deletions(-) create mode 100644 dev/src/draw2d.cpp diff --git a/dev/msvc/olcPGE3.vcxproj b/dev/msvc/olcPGE3.vcxproj index 2f4484c7..93f3c834 100644 --- a/dev/msvc/olcPGE3.vcxproj +++ b/dev/msvc/olcPGE3.vcxproj @@ -200,6 +200,7 @@ + @@ -210,19 +211,22 @@ true true - + + true + true + false false - false - false + true + true false false - false - false + true + true diff --git a/dev/msvc/olcPGE3.vcxproj.filters b/dev/msvc/olcPGE3.vcxproj.filters index 21f7cc2b..da024f74 100644 --- a/dev/msvc/olcPGE3.vcxproj.filters +++ b/dev/msvc/olcPGE3.vcxproj.filters @@ -116,5 +116,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/dev/src/core.cpp b/dev/src/core.cpp index 22175bb4..0e8b95bd 100644 --- a/dev/src/core.cpp +++ b/dev/src/core.cpp @@ -148,6 +148,9 @@ namespace olc return; } + + CreateImage(imgPrimary, GetSize()); + if (!OnUserCreate()) { // Creation process signalled abort diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp new file mode 100644 index 00000000..57199997 --- /dev/null +++ b/dev/src/draw2d.cpp @@ -0,0 +1,131 @@ +#include "draw2d.h" + +#include "gpu_iface.h" + +//! START IMPLEMENTATION +using namespace olc; + +Draw2D::Draw2D() +{ +} + +void Draw2D::SetGPU(olc::gpu::Renderer* const renderer) +{ + pRenderer = renderer; +} + +void Draw2D::SetTarget(olc::Image& image) +{ + pTarget = ℑ +} + +void Draw2D::ClearTransform() +{ + transform = olc::tf2d(); +} + +void Draw2D::SetTransform(const olc::tf2d& trans) +{ + transform = trans; +} + +const tf2d& olc::Draw2D::GetTransform() +{ + return transform; +} + +void olc::Draw2D::ProcessGPUTasks() +{ + for (const auto& task : vecGPUTasks) + pRenderer->DoGPUTask(task); + + vecGPUTasks.clear(); +} + +void Draw2D::PrepareTargetForSW() +{ + if (pTarget->BoundToGPU()) + { + // Process GPU queue bound for the target + ProcessGPUTasks(); + + // Image resource is primed for GPU operations, bring it to CPU + pRenderer->ReadTexture(pTarget->GetGPUID(), *pTarget); + + // Image is now CPU bound + pTarget->BindCPU(); + } +} + +void Draw2D::PrepareTargetForHW() +{ + if (pTarget->BoundToCPU()) + { + // Image resource is primed for CPU operations, send it to GPU + pRenderer->WriteTexture(pTarget->GetGPUID(), *pTarget); + + // Image is now GPU bound + pTarget->BindGPU(); + } +} + +void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) +{ + PrepareTargetForSW(); + pTarget->Data(transform.forward(pos)) = col; +} + +GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) +{ + GPUTask task; + task.bWireframe = true; + for (const auto& v : vPoints) + task.vertexBuffer.push_back({ v.x, v.y, 0.0f, 0.0f, 0.0f, 0.0f, colour }); + task.tint = tint; + return task; +} + +GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskDrawPolygon( + GPUTask::Structure::Line, + transform.forward({ p1, p2 }), + col, + olc::Colour::WHITE + )); +} + +GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskDrawPolygon( + GPUTask::Structure::Line, + transform.forward({ p1, p2 }), + { c1, c2 }, + olc::Colour::WHITE + )); +} + diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index 666e06eb..bf9bacb4 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -12,45 +12,99 @@ //! START CUSTOMHEADER #include "config.h" #include "vector2d.h" +#include "transform2d.h" #include "pixel.h" +#include "image.h" +#include "gputask.h" //! END CUSTOMHEADER //! START DECLARATION #if !defined(PGE_DRAW2D_DECLARED) namespace olc { + namespace gpu + { + class Renderer; + } + + class Draw2D { public: Draw2D(); + // Associate this drawing toolbox with a renderer + void SetGPU(olc::gpu::Renderer* const renderer); + + public: + // Sets the drawing target of this drawing toolbox + void SetTarget(olc::Image& image); + + // Clears transform stack and sets identity transform + void ClearTransform(); + + void SetTransform(const olc::tf2d& trans); + + const olc::tf2d& GetTransform(); + + void ProcessGPUTasks(); + + protected: + // Checks residency of image resource, and brings it to cpu RAM for r/w + void PrepareTargetForSW(); + // Checks residency of image resource, and brings it to gpu VRAM for r/w + void PrepareTargetForHW(); + + olc::Image* pTarget = nullptr; + olc::gpu::Renderer* pRenderer = nullptr; + olc::tf2d transform; + + std::vector vecGPUTasks; + public: // Plot a single pixel - template - void Draw(const olc::v_2d& pos, const olc::Pixel col = olc::Colour::WHITE) - { - /* - if(target image not in ram) - copy_gpu_to_cpu(target image) + void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); - - */ - } + public: // GPU Task Creator Functions + GPUTask TaskDrawPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const std::vector& vColours, + const olc::Pixel tint = olc::Colour::WHITE); + GPUTask TaskDrawPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const olc::Pixel colour, + const olc::Pixel tint = olc::Colour::WHITE); - // Draws a single pixel wide line - template - void DrawLine(const olc::v_2d& p1, const olc::v_2d& p2, const olc::Pixel col = olc::Colour::WHITE) - { - /* - if(target image not in ram) - copy_gpu_to_cpu(target image) + GPUTask TaskFillPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const std::vector& vColours, + const olc::Pixel tint = olc::Colour::WHITE); + GPUTask TaskFillPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const olc::Pixel colour, + const olc::Pixel tint = olc::Colour::WHITE); + GPUTask TaskTexturedPolygon( + GPUTask::Structure structure, + const std::vector& vColours, + const std::vector& vTexCoords, + olc::Image* const image, + const olc::Pixel tint = olc::Colour::WHITE); - */ - } + + + public: + // Draws a single pixel wide line + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); + // Draws a single pixel wide line with a gradient + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); }; } #define PGE_DRAW2D_DECLARED diff --git a/dev/src/gpu_iface.h b/dev/src/gpu_iface.h index 74a60f46..9d53c82d 100644 --- a/dev/src/gpu_iface.h +++ b/dev/src/gpu_iface.h @@ -68,7 +68,7 @@ namespace olc public: // Shader Construction Stuff public: // GPU Task Processing Stuff - virtual bool DoGPUTask(const olc::pgeguts::GPUTask& task) = 0; + virtual bool DoGPUTask(const olc::GPUTask& task) = 0; public: // Swap Chain Stuff // Clears the viewport to a specific colour and depth diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index d9ffd94b..1eeecc1b 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -143,7 +143,7 @@ namespace olc::gpu return false; } - bool Renderer_OGL33::DoGPUTask(const olc::pgeguts::GPUTask& task) + bool Renderer_OGL33::DoGPUTask(const olc::GPUTask& task) { auto& gl = olc::apis::opengl::gl::Get(); return false; diff --git a/dev/src/gpu_opengl33.h b/dev/src/gpu_opengl33.h index 49d57bcb..fb18696f 100644 --- a/dev/src/gpu_opengl33.h +++ b/dev/src/gpu_opengl33.h @@ -33,7 +33,7 @@ namespace olc public: // GPU Task Stuff - virtual bool DoGPUTask(const olc::pgeguts::GPUTask& task) override; + virtual bool DoGPUTask(const olc::GPUTask& task) override; public: // Swap Chain Stuff // Clears the viewport to a specific colour and depth diff --git a/dev/src/gputask.h b/dev/src/gputask.h index 2f30ab7b..3310d4d1 100644 --- a/dev/src/gputask.h +++ b/dev/src/gputask.h @@ -17,8 +17,7 @@ #if !defined(PGE_GPUTASK_DECLARED) namespace olc { - namespace pgeguts - { + // This is the default "packet" of work that is sent to // a GPU for drawing. Various drawing operations throughout // PGE create GPUTasks which are stored and dispatched when @@ -115,7 +114,7 @@ namespace olc // return task; //} - } + } #define PGE_GPUTASK_DECLARED 1 #endif diff --git a/dev/src/image.cpp b/dev/src/image.cpp index 7da56313..e774c8e4 100644 --- a/dev/src/image.cpp +++ b/dev/src/image.cpp @@ -29,6 +29,11 @@ namespace olc return pixels.data(); } + olc::Pixel& Image::Data(const olc::vf2d pos) + { + return pixels[pos.y * dimensions.x + pos.x]; + } + const ImageConfig& Image::GetConfig() const { return config; @@ -44,5 +49,27 @@ namespace olc gpuResourceID = id; } + bool Image::BoundToGPU() const + { + return onGPU; + } + + bool Image::BoundToCPU() const + { + return onCPU; + } + + void Image::BindGPU() + { + onGPU = true; + onCPU = false; + } + + void Image::BindCPU() + { + onCPU = true; + onGPU = false; + } + }; //! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/image.h b/dev/src/image.h index 3bba1b93..95337ece 100644 --- a/dev/src/image.h +++ b/dev/src/image.h @@ -42,6 +42,8 @@ namespace olc const olc::vi2d& Size() const; // Returns read/write pointer to start of 1D stream of pixel data olc::Pixel* Data(); + // [UNSAFE] Returns pixel at location + olc::Pixel& Data(const olc::vf2d pos); // Returns how this image was configured upon creation const ImageConfig& GetConfig() const; // Return GPU Resource ID @@ -49,21 +51,20 @@ namespace olc // Set GPU Resource ID (0 to eliminate) void SetGPUID(const int32_t id); - // True if data mirror has in-front RAM image - bool HasWetCPU() const; - // True if data mirror has in-front VRAM image - bool HasWetGPU() const; + bool BoundToGPU() const; + bool BoundToCPU() const; - void PrimeCPU(); - void PrimeGPU(); + public: // Make friendly private later + void BindGPU(); + void BindCPU(); protected: ImageConfig config; olc::vi2d dimensions; std::vector pixels; int32_t gpuResourceID = 0; - bool gpuWet = false; - bool cpuWet = true; + bool onGPU = false; + bool onCPU = true; }; } #define PGE_IMAGE_DECLARED 1 diff --git a/dev/src/window.cpp b/dev/src/window.cpp index d1e3e1a0..f6a75ffd 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -76,6 +76,10 @@ namespace olc { // Environmental changes + draw.ClearTransform(); + draw.SetGPU(gpu); + draw.SetTarget(imgPrimary); + gpu->SetViewport({ 0,0 }, GetSize()); gpu->ClearViewport(olc::Colour::TANGERINE, false, false); diff --git a/dev/src/window.h b/dev/src/window.h index 6139c8c3..29793f83 100644 --- a/dev/src/window.h +++ b/dev/src/window.h @@ -15,6 +15,7 @@ #include "pixel.h" #include "vector2d.h" #include "gpu_iface.h" +#include "draw2d.h" //! END CUSTOMHEADER //! START DECLARATION @@ -104,6 +105,10 @@ namespace olc olc::host::Host* pHost = nullptr; //olc::gpu::Renderer* pRenderer = nullptr; + + protected: + olc::Draw2D draw; + olc::Image imgPrimary; }; } #define PGE_WINDOW_DECLARED 1 diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index c4d64faa..8074dd17 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -20,6 +20,8 @@ class Example : public olc::PixelGameEngine bool OnUserUpdate(float fElapsedTime) override { + draw.Line({ 10,10 }, { 20,20 }, olc::Colour::BLUE); + return true; } }; From 703105ae21f19be7bd5ea9e824b1a4e0741c6035 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Thu, 4 Sep 2025 22:38:05 +0100 Subject: [PATCH 02/11] Started work on shader support --- dev/msvc/olcPGE3.vcxproj | 1 + dev/msvc/olcPGE3.vcxproj.filters | 3 + .../olcPGE3_BuildSH/olcPixelGameEngine3.h | 957 +++++++++++++----- dev/src/api_opengl.cpp | 6 + dev/src/api_opengl.h | 3 + dev/src/draw2d.cpp | 2 + dev/src/gpu_iface.cpp | 37 + dev/src/gpu_iface.h | 30 + dev/src/gpu_opengl33.cpp | 114 ++- dev/src/gpu_opengl33.h | 12 + dev/src/sh_template.h | 21 +- dev/src/window.cpp | 5 +- 12 files changed, 930 insertions(+), 261 deletions(-) create mode 100644 dev/src/gpu_iface.cpp diff --git a/dev/msvc/olcPGE3.vcxproj b/dev/msvc/olcPGE3.vcxproj index 93f3c834..4f525342 100644 --- a/dev/msvc/olcPGE3.vcxproj +++ b/dev/msvc/olcPGE3.vcxproj @@ -201,6 +201,7 @@ + diff --git a/dev/msvc/olcPGE3.vcxproj.filters b/dev/msvc/olcPGE3.vcxproj.filters index da024f74..03904b2f 100644 --- a/dev/msvc/olcPGE3.vcxproj.filters +++ b/dev/msvc/olcPGE3.vcxproj.filters @@ -119,5 +119,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h b/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h index 6ac0a1a4..f6c6e24d 100644 --- a/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h +++ b/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h @@ -1142,6 +1142,8 @@ namespace olc const olc::vi2d& Size() const; // Returns read/write pointer to start of 1D stream of pixel data olc::Pixel* Data(); + // [UNSAFE] Returns pixel at location + olc::Pixel& Data(const olc::vf2d pos); // Returns how this image was configured upon creation const ImageConfig& GetConfig() const; // Return GPU Resource ID @@ -1149,122 +1151,29 @@ namespace olc // Set GPU Resource ID (0 to eliminate) void SetGPUID(const int32_t id); - // True if data mirror has in-front RAM image - bool HasWetCPU() const; - // True if data mirror has in-front VRAM image - bool HasWetGPU() const; + bool BoundToGPU() const; + bool BoundToCPU() const; - void PrimeCPU(); - void PrimeGPU(); + public: // Make friendly private later + void BindGPU(); + void BindCPU(); protected: ImageConfig config; olc::vi2d dimensions; std::vector pixels; int32_t gpuResourceID = 0; - bool gpuWet = false; - bool cpuWet = true; + bool onGPU = false; + bool onCPU = true; }; } #define PGE_IMAGE_DECLARED 1 #endif - -#if !defined(PGE_WINDOW_DECLARED) - -#if OLC_HOST == OLC_HOST_WINDOWS - #define FRIENDLY_HOST Host_Windows_WinAPI -#endif - -namespace olc -{ - namespace host - { - class FRIENDLY_HOST; - class Host; - } - - namespace gpu - { - class Renderer; - } - - class Window - { - friend class olc::host::FRIENDLY_HOST; - - public: - Window(); - virtual ~Window(); - - void ConnecToHost(olc::host::Host* host); - - public: - // Return true if window is to continue - virtual bool OnUserCreate(); - // Return true if window is to continue - virtual bool OnUserUpdate(float fElapsedTime); - // Return true if window is to close - virtual bool OnUserDestroy(); - - private: - // Set Mouse Device State - bool olc_OnMouseButton(const uint8_t nButton, const bool bPressed); - bool olc_OnMouseMove(const olc::vi2d& vMousePos); - bool olc_OnMouseWheel(const int32_t nScroll); - bool olc_OnMouseFocus(const bool bHasFocus); - - // Set Window State - bool olc_OnWindowPosition(const olc::vi2d& vWindowPos); - bool olc_OnWindowSize(const olc::vi2d& vWindowSize); - - // Set Keyboard State - - - - public: - bool olc_ShouldRemove() const; - bool olc_WindowUpdate(const float fElapsedTime, olc::gpu::Renderer* const gpu); - - public: - size_t GetUID() const; - - const olc::vi2d& GetSize() const; - bool SetSize(const olc::vi2d& vSize); - - const olc::vi2d& GetPosition() const; - bool SetPosition(const olc::vi2d& vPosition); - - const std::string& GetTitle() const; - bool SetTitle(const std::string& sTitle); - - - protected: - virtual bool olc_PrimaryWindowInit(); - - protected: - bool bShouldRemove = false; - - protected: - size_t nUniqueID = -1; - olc::vi2d vWindowPos; - olc::vi2d vWindowSize; - std::string sFrameTitle; - - private: - olc::vi2d volatile_vMousePos; - - olc::host::Host* pHost = nullptr; - //olc::gpu::Renderer* pRenderer = nullptr; - }; -} -#define PGE_WINDOW_DECLARED 1 -#endif #if !defined(PGE_GPUTASK_DECLARED) namespace olc { - namespace pgeguts - { + // This is the default "packet" of work that is sent to // a GPU for drawing. Various drawing operations throughout // PGE create GPUTasks which are stored and dispatched when @@ -1361,7 +1270,7 @@ namespace olc // return task; //} - } + } #define PGE_GPUTASK_DECLARED 1 #endif @@ -1386,6 +1295,33 @@ namespace olc FailedToSwitchRenderContext, }; + class Shader + { + public: + virtual ~Shader(); + + public: + void SetPixelShaderSource(const std::string& src); + void SetVertexShaderSource(const std::string& src); + void SetGeometryShaderSource(const std::string& src); + + virtual std::string Compile() = 0; + virtual int32_t CreateUniform(const std::string& name) = 0; + + int32_t GetUniform(const std::string& name) const; + int32_t GetShaderID() const; + + protected: + std::string srcPixelShader; + std::string srcVertexShader; + std::string srcGeometryShader; + int32_t nPixelShaderID; + int32_t nVertexShaderID; + int32_t nGeometryShaderID; + int32_t nCompiledShaderID; + std::unordered_map mapUniforms; + }; + class Renderer { public: @@ -1419,8 +1355,11 @@ namespace olc public: // Shader Construction Stuff + virtual bool ApplyShader(const Shader& shader) = 0; + virtual bool ApplyDefaultShader() = 0; + public: // GPU Task Processing Stuff - virtual bool DoGPUTask(const olc::pgeguts::GPUTask& task) = 0; + virtual bool DoGPUTask(const olc::GPUTask& task) = 0; public: // Swap Chain Stuff // Clears the viewport to a specific colour and depth @@ -1441,6 +1380,192 @@ namespace olc } #define PGE_RENDERER_IFACE_DECLARED 1 #endif + +#if !defined(PGE_DRAW2D_DECLARED) +namespace olc +{ + namespace gpu + { + class Renderer; + } + + + class Draw2D + { + public: + Draw2D(); + + // Associate this drawing toolbox with a renderer + void SetGPU(olc::gpu::Renderer* const renderer); + + public: + // Sets the drawing target of this drawing toolbox + void SetTarget(olc::Image& image); + + // Clears transform stack and sets identity transform + void ClearTransform(); + + void SetTransform(const olc::tf2d& trans); + + const olc::tf2d& GetTransform(); + + void ProcessGPUTasks(); + + protected: + // Checks residency of image resource, and brings it to cpu RAM for r/w + void PrepareTargetForSW(); + // Checks residency of image resource, and brings it to gpu VRAM for r/w + void PrepareTargetForHW(); + + olc::Image* pTarget = nullptr; + olc::gpu::Renderer* pRenderer = nullptr; + olc::tf2d transform; + + std::vector vecGPUTasks; + + public: + // Plot a single pixel + void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); + + + public: // GPU Task Creator Functions + GPUTask TaskDrawPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const std::vector& vColours, + const olc::Pixel tint = olc::Colour::WHITE); + + GPUTask TaskDrawPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const olc::Pixel colour, + const olc::Pixel tint = olc::Colour::WHITE); + + GPUTask TaskFillPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const std::vector& vColours, + const olc::Pixel tint = olc::Colour::WHITE); + + GPUTask TaskFillPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const olc::Pixel colour, + const olc::Pixel tint = olc::Colour::WHITE); + + GPUTask TaskTexturedPolygon( + GPUTask::Structure structure, + const std::vector& vColours, + const std::vector& vTexCoords, + olc::Image* const image, + const olc::Pixel tint = olc::Colour::WHITE); + + + + public: + // Draws a single pixel wide line + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); + // Draws a single pixel wide line with a gradient + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + }; +} +#define PGE_DRAW2D_DECLARED +#endif + +#if !defined(PGE_WINDOW_DECLARED) + +#if OLC_HOST == OLC_HOST_WINDOWS + #define FRIENDLY_HOST Host_Windows_WinAPI +#endif + +namespace olc +{ + namespace host + { + class FRIENDLY_HOST; + class Host; + } + + namespace gpu + { + class Renderer; + } + + class Window + { + friend class olc::host::FRIENDLY_HOST; + + public: + Window(); + virtual ~Window(); + + void ConnecToHost(olc::host::Host* host); + + public: + // Return true if window is to continue + virtual bool OnUserCreate(); + // Return true if window is to continue + virtual bool OnUserUpdate(float fElapsedTime); + // Return true if window is to close + virtual bool OnUserDestroy(); + + private: + // Set Mouse Device State + bool olc_OnMouseButton(const uint8_t nButton, const bool bPressed); + bool olc_OnMouseMove(const olc::vi2d& vMousePos); + bool olc_OnMouseWheel(const int32_t nScroll); + bool olc_OnMouseFocus(const bool bHasFocus); + + // Set Window State + bool olc_OnWindowPosition(const olc::vi2d& vWindowPos); + bool olc_OnWindowSize(const olc::vi2d& vWindowSize); + + // Set Keyboard State + + + + public: + bool olc_ShouldRemove() const; + bool olc_WindowUpdate(const float fElapsedTime, olc::gpu::Renderer* const gpu); + + public: + size_t GetUID() const; + + const olc::vi2d& GetSize() const; + bool SetSize(const olc::vi2d& vSize); + + const olc::vi2d& GetPosition() const; + bool SetPosition(const olc::vi2d& vPosition); + + const std::string& GetTitle() const; + bool SetTitle(const std::string& sTitle); + + + protected: + virtual bool olc_PrimaryWindowInit(); + + protected: + bool bShouldRemove = false; + + protected: + size_t nUniqueID = -1; + olc::vi2d vWindowPos; + olc::vi2d vWindowSize; + std::string sFrameTitle; + + private: + olc::vi2d volatile_vMousePos; + + olc::host::Host* pHost = nullptr; + //olc::gpu::Renderer* pRenderer = nullptr; + + protected: + olc::Draw2D draw; + olc::Image imgPrimary; + }; +} +#define PGE_WINDOW_DECLARED 1 +#endif #if !defined(PGE_HOST_IFACE_DECLARED) namespace olc @@ -1740,6 +1865,7 @@ namespace olc typedef GLuint CALLSTYLE glCreateShader_t(GLenum type); typedef GLuint CALLSTYLE glCreateProgram_t(void); + typedef void CALLSTYLE glShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); typedef void CALLSTYLE glDeleteShader_t(GLuint shader); typedef void CALLSTYLE glCompileShader_t(GLuint shader); typedef void CALLSTYLE glLinkProgram_t(GLuint program); @@ -1791,6 +1917,7 @@ namespace olc public: glCreateShader_t* glCreateShader = nullptr; glCreateProgram_t* glCreateProgram = nullptr; + glShaderSource_t* glShaderSource = nullptr; glDeleteShader_t* glDeleteShader = nullptr; glCompileShader_t* glCompileShader = nullptr; glLinkProgram_t* glLinkProgram = nullptr; @@ -1830,6 +1957,7 @@ namespace olc void glClear(GLbitfield mask); void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data); }; } @@ -1854,6 +1982,13 @@ namespace olc { namespace gpu { + class Shader_GLSL33 : public olc::gpu::Shader + { + public: + std::string Compile() override; + int32_t CreateUniform(const std::string& name) override; + }; + class Renderer_OGL33 : public olc::gpu::Renderer { public: // Device Stuff @@ -1876,9 +2011,12 @@ namespace olc // Makes active the given texture resource (for subsequent rendering operations) bool AssignTextureTarget(const uint32_t slot, const uint32_t texid) override; + public: // Shader Construction Stuff + bool ApplyShader(const Shader& shader) override; + bool ApplyDefaultShader() override; public: // GPU Task Stuff - virtual bool DoGPUTask(const olc::pgeguts::GPUTask& task) override; + virtual bool DoGPUTask(const olc::GPUTask& task) override; public: // Swap Chain Stuff // Clears the viewport to a specific colour and depth @@ -1895,6 +2033,8 @@ namespace olc olc::apis::opengl::glDeviceContext_t glDeviceContext = 0; olc::apis::opengl::glRenderContext_t glRenderContext = 0; + Shader_GLSL33 shaderDefault; + }; } } @@ -1907,150 +2047,7 @@ namespace olc -#if defined(OLC_PGE_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) -namespace olc -{ - Window::Window() - { - nUniqueID = pgeguts::CreateUID(); - } - Window::~Window() - { - } - - void Window::ConnecToHost(olc::host::Host* host) - { - pHost = host; - sFrameTitle = "OneLoneCoder.com - Pixel Game Engine 3"; - pHost->UpdateWindowFrameTitle(this); - } - - bool Window::OnUserCreate() - { - return false; - } - - bool Window::OnUserUpdate(float fElapsedTime) - { - return false; - } - - bool Window::OnUserDestroy() - { - return false; - } - - bool Window::olc_OnMouseButton(const uint8_t nButton, const bool bPressed) - { - return false; - } - - bool Window::olc_OnMouseMove(const olc::vi2d& vMousePos) - { - volatile_vMousePos = vMousePos; - return true; - } - - bool Window::olc_OnMouseWheel(const int32_t nScroll) - { - return false; - } - - bool Window::olc_OnMouseFocus(const bool bHasFocus) - { - return false; - } - - bool Window::olc_OnWindowPosition(const olc::vi2d& vWindowPos) - { - return false; - } - - bool Window::olc_OnWindowSize(const olc::vi2d& vWindowSize) - { - return false; - } - - bool Window::olc_ShouldRemove() const - { - return bShouldRemove; - } - - bool Window::olc_WindowUpdate(const float fElapsedTime, olc::gpu::Renderer* const gpu) - { - // Environmental changes - - gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::TANGERINE, false, false); - - // User Update - if (!OnUserUpdate(fElapsedTime)) - { - // User has requested termination of window by returning false - if (OnUserDestroy()) - { - // User has confirmed window destruction by returning true - bShouldRemove = true; - } - } - - - gpu->DisplayDraw(); - - return true; - } - - size_t Window::GetUID() const - { - return nUniqueID; - } - - const olc::vi2d& Window::GetSize() const - { - return vWindowSize; - } - - const olc::vi2d& Window::GetPosition() const - { - return vWindowPos; - } - - bool Window::SetSize(const olc::vi2d& vSize) - { - // Request host to change geometry of window object - - vWindowSize = vSize; - return true; - } - - bool Window::SetPosition(const olc::vi2d& vPosition) - { - // Request host to change geometry of window object - - vWindowPos = vPosition; - return true; - } - - const std::string& Window::GetTitle() const - { - return sFrameTitle; - } - - bool Window::SetTitle(const std::string& sTitle) - { - sFrameTitle = sTitle; - pHost->UpdateWindowFrameTitle(this); - return false; - } - - bool Window::olc_PrimaryWindowInit() - { - return false; - } -}; -#define PGE_WINDOW_IMPLEMENTED 1 -#endif #if defined(OLC_PGE_APPLICATION) && !defined(PGE_HOST_IMPLEMENTED) #if OLC_HOST == OLC_HOST_WINDOWS @@ -2309,6 +2306,38 @@ namespace olc::host #if defined(OLC_PGE_APPLICATION) && !defined(PGE_GPU_IMPLEMENTED) #if OLC_GPU == OLC_GPU_OPENGL33 +namespace olc +{ + gpu::Shader::~Shader() + { + } + + void gpu::Shader::SetPixelShaderSource(const std::string& src) + { + srcPixelShader = src; + } + + void gpu::Shader::SetVertexShaderSource(const std::string& src) + { + srcVertexShader = src; + } + + void gpu::Shader::SetGeometryShaderSource(const std::string& src) + { + srcGeometryShader = src; + } + + int32_t gpu::Shader::GetUniform(const std::string& name) const + { + return mapUniforms.at(name); + } + + int32_t gpu::Shader::GetShaderID() const + { + return nCompiledShaderID; + } +} + namespace olc::apis::opengl { bool gl::bLoaded = false; @@ -2326,6 +2355,7 @@ namespace olc::apis::opengl bLoaded = true; bLoaded &= (glCreateShader = OGL_LOAD(glCreateShader)) != nullptr; bLoaded &= (glCreateProgram = OGL_LOAD(glCreateProgram)) != nullptr; + bLoaded &= (glShaderSource = OGL_LOAD(glShaderSource)) != nullptr; bLoaded &= (glDeleteShader = OGL_LOAD(glDeleteShader)) != nullptr; bLoaded &= (glCompileShader = OGL_LOAD(glCompileShader)) != nullptr; bLoaded &= (glLinkProgram = OGL_LOAD(glLinkProgram)) != nullptr; @@ -2407,9 +2437,69 @@ namespace olc::apis::opengl { ::glClearColor(red, green, blue, alpha); } + + void gl::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data) + { + ::glReadPixels(x, y, width, height, format, type, data); + } } namespace olc::gpu { + std::string Shader_GLSL33::Compile() + { + auto& gl = olc::apis::opengl::gl::Get(); + + nCompiledShaderID = gl.glCreateProgram(); + + // Fragment Shader + if (!srcPixelShader.empty()) + { + nPixelShaderID = gl.glCreateShader(0x8B30); + const char* s = srcPixelShader.c_str(); + gl.glShaderSource(nPixelShaderID, 1, &s, nullptr); + gl.glCompileShader(nPixelShaderID); + // TODO: Error Check + gl.glAttachShader(nCompiledShaderID, nPixelShaderID); + } + + // Vertex Shader + if (!srcVertexShader.empty()) + { + nVertexShaderID = gl.glCreateShader(0x8B31); + const char* s = srcVertexShader.c_str(); + gl.glShaderSource(nVertexShaderID, 1, &s, nullptr); + gl.glCompileShader(nVertexShaderID); + // TODO: Error Check + gl.glAttachShader(nCompiledShaderID, nVertexShaderID); + } + + + // Geometry Shader + if (!srcGeometryShader.empty()) + { + nGeometryShaderID = gl.glCreateShader(0x8DD9); + const char* s = srcGeometryShader.c_str(); + gl.glShaderSource(nGeometryShaderID, 1, &s, nullptr); + gl.glCompileShader(nGeometryShaderID); + // TODO: Error Check + gl.glAttachShader(nCompiledShaderID, nGeometryShaderID); + } + + gl.glLinkProgram(nCompiledShaderID); + + return "OK"; + } + + int32_t Shader_GLSL33::CreateUniform(const std::string& name) + { + auto& gl = olc::apis::opengl::gl::Get(); + const char* s = name.c_str(); + mapUniforms.insert({ name, gl.glGetUniformLocation(nCompiledShaderID, s) }); + return GetUniform(name); + } + + + bool Renderer_OGL33::CreateDevice(std::vector params, const RendererConfig& cfg) { config = cfg; @@ -2464,6 +2554,34 @@ namespace olc::gpu auto& gl = olc::apis::opengl::gl::Get(); + shaderDefault.SetPixelShaderSource( + "#version 330 core\n" + "out vec4 pixel;\n" + "in vec2 oTex;\n" + "in vec4 oCol;\n" + "uniform sampler2D sprTex;\n" + "void main(){pixel = texture(sprTex, oTex) * oCol;}" + ); + + shaderDefault.SetVertexShaderSource( + "#version 330 core\n" + "layout(location = 0) in vec4 aPos;\n" + "layout(location = 1) in vec2 aTex;\n" + "layout(location = 2) in vec4 aCol;\n" + "uniform mat4 mvp;\n" + "uniform int is3d;\n" + "uniform vec4 tint;\n" + "out vec2 oTex;\n" + "out vec4 oCol;\n" + "void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex;} oCol = aCol * tint;}" + ); + + shaderDefault.Compile(); + shaderDefault.CreateUniform("mvp"); + shaderDefault.CreateUniform("is3d"); + shaderDefault.CreateUniform("tint"); + + lastError = RendererError::None; return true; } @@ -2521,14 +2639,17 @@ namespace olc::gpu bool Renderer_OGL33::WriteTexture(const uint32_t texid, olc::Image& image) { auto& gl = olc::apis::opengl::gl::Get(); + gl.glBindTexture(GL_TEXTURE_2D, image.GetGPUID()); gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.Size().x, image.Size().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); - return false; + return true; } bool Renderer_OGL33::ReadTexture(const uint32_t texid, olc::Image& image) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + gl.glBindTexture(GL_TEXTURE_2D, image.GetGPUID()); + gl.glReadPixels(0, 0, image.Size().x, image.Size().y, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); + return true; } bool Renderer_OGL33::DeleteTexture(const uint32_t texid) @@ -2550,10 +2671,30 @@ namespace olc::gpu return false; } - bool Renderer_OGL33::DoGPUTask(const olc::pgeguts::GPUTask& task) + bool Renderer_OGL33::ApplyShader(const Shader& shader) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + gl.glUseProgram(shader.GetShaderID()); + return true; + } + + bool Renderer_OGL33::ApplyDefaultShader() + { + auto& gl = olc::apis::opengl::gl::Get(); + gl.glUseProgram(shaderDefault.GetShaderID()); + return true; + } + + bool Renderer_OGL33::DoGPUTask(const olc::GPUTask& task) + { + auto& gl = olc::apis::opengl::gl::Get(); + + + + + + + return true; } bool Renderer_OGL33::ClearViewport(const olc::Pixel col, bool bDepth, bool bStencil) @@ -2588,11 +2729,144 @@ namespace olc::gpu return false; } + + } #endif #define PGE_GPU_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_DRAW2D_IMPLEMENTED) +using namespace olc; + +Draw2D::Draw2D() +{ +} + +void Draw2D::SetGPU(olc::gpu::Renderer* const renderer) +{ + pRenderer = renderer; +} + +void Draw2D::SetTarget(olc::Image& image) +{ + pTarget = ℑ +} + +void Draw2D::ClearTransform() +{ + transform = olc::tf2d(); +} + +void Draw2D::SetTransform(const olc::tf2d& trans) +{ + transform = trans; +} + +const tf2d& olc::Draw2D::GetTransform() +{ + return transform; +} + +void olc::Draw2D::ProcessGPUTasks() +{ + for (const auto& task : vecGPUTasks) + pRenderer->DoGPUTask(task); + + vecGPUTasks.clear(); +} + +void Draw2D::PrepareTargetForSW() +{ + if (pTarget->BoundToGPU()) + { + // Process GPU queue bound for the target + ProcessGPUTasks(); + + // Image resource is primed for GPU operations, bring it to CPU + pRenderer->ReadTexture(pTarget->GetGPUID(), *pTarget); + + // Image is now CPU bound + pTarget->BindCPU(); + } +} + +void Draw2D::PrepareTargetForHW() +{ + if (pTarget->BoundToCPU()) + { + // Image resource is primed for CPU operations, send it to GPU + pRenderer->WriteTexture(pTarget->GetGPUID(), *pTarget); + + // Image is now GPU bound + pTarget->BindGPU(); + } +} + +void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) +{ + PrepareTargetForSW(); + pTarget->Data(transform.forward(pos)) = col; +} + +GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) +{ + GPUTask task; + task.bWireframe = true; + for (const auto& v : vPoints) + task.vertexBuffer.push_back({ v.x, v.y, 0.0f, 0.0f, 0.0f, 0.0f, colour }); + task.tint = tint; + return task; +} + +GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) +{ + return GPUTask(); +} + +GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskDrawPolygon( + GPUTask::Structure::Line, + transform.forward({ p1, p2 }), + col, + olc::Colour::WHITE + )); +} + +GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskDrawPolygon( + GPUTask::Structure::Line, + transform.forward({ p1, p2 }), + { c1, c2 }, + olc::Colour::WHITE + )); +} + + +#define PGE_DRAW2D_IMPLEMENTED 1 +#endif + #if defined(OLC_PGE_APPLICATION) && !defined(PGE_CORE_IMPLEMENTED) namespace olc { @@ -2738,6 +3012,9 @@ namespace olc return; } + + CreateImage(imgPrimary, GetSize()); + if (!OnUserCreate()) { // Creation process signalled abort @@ -2853,6 +3130,11 @@ namespace olc return pixels.data(); } + olc::Pixel& Image::Data(const olc::vf2d pos) + { + return pixels[pos.y * dimensions.x + pos.x]; + } + const ImageConfig& Image::GetConfig() const { return config; @@ -2868,8 +3150,181 @@ namespace olc gpuResourceID = id; } + bool Image::BoundToGPU() const + { + return onGPU; + } + + bool Image::BoundToCPU() const + { + return onCPU; + } + + void Image::BindGPU() + { + onGPU = true; + onCPU = false; + } + + void Image::BindCPU() + { + onCPU = true; + onGPU = false; + } + }; #define PGE_IMAGE_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) +namespace olc +{ + Window::Window() + { + nUniqueID = pgeguts::CreateUID(); + } + + Window::~Window() + { + } + + void Window::ConnecToHost(olc::host::Host* host) + { + pHost = host; + sFrameTitle = "OneLoneCoder.com - Pixel Game Engine 3"; + pHost->UpdateWindowFrameTitle(this); + } + + bool Window::OnUserCreate() + { + return false; + } + + bool Window::OnUserUpdate(float fElapsedTime) + { + return false; + } + + bool Window::OnUserDestroy() + { + return false; + } + + bool Window::olc_OnMouseButton(const uint8_t nButton, const bool bPressed) + { + return false; + } + + bool Window::olc_OnMouseMove(const olc::vi2d& vMousePos) + { + volatile_vMousePos = vMousePos; + return true; + } + + bool Window::olc_OnMouseWheel(const int32_t nScroll) + { + return false; + } + + bool Window::olc_OnMouseFocus(const bool bHasFocus) + { + return false; + } + + bool Window::olc_OnWindowPosition(const olc::vi2d& vWindowPos) + { + return false; + } + + bool Window::olc_OnWindowSize(const olc::vi2d& vWindowSize) + { + return false; + } + + bool Window::olc_ShouldRemove() const + { + return bShouldRemove; + } + + bool Window::olc_WindowUpdate(const float fElapsedTime, olc::gpu::Renderer* const gpu) + { + // Environmental changes + + draw.ClearTransform(); + draw.SetGPU(gpu); + draw.SetTarget(imgPrimary); + + gpu->SetViewport({ 0,0 }, GetSize()); + gpu->ClearViewport(olc::Colour::TANGERINE, false, false); + + // User Update + if (!OnUserUpdate(fElapsedTime)) + { + // User has requested termination of window by returning false + if (OnUserDestroy()) + { + // User has confirmed window destruction by returning true + bShouldRemove = true; + } + } + + // Finialise any outstanding tasks + draw.ProcessGPUTasks(); + + // Update Window's primary surface + gpu->DisplayDraw(); + + return true; + } + + size_t Window::GetUID() const + { + return nUniqueID; + } + + const olc::vi2d& Window::GetSize() const + { + return vWindowSize; + } + + const olc::vi2d& Window::GetPosition() const + { + return vWindowPos; + } + + bool Window::SetSize(const olc::vi2d& vSize) + { + // Request host to change geometry of window object + + vWindowSize = vSize; + return true; + } + + bool Window::SetPosition(const olc::vi2d& vPosition) + { + // Request host to change geometry of window object + + vWindowPos = vPosition; + return true; + } + + const std::string& Window::GetTitle() const + { + return sFrameTitle; + } + + bool Window::SetTitle(const std::string& sTitle) + { + sFrameTitle = sTitle; + pHost->UpdateWindowFrameTitle(this); + return false; + } + + bool Window::olc_PrimaryWindowInit() + { + return false; + } +}; +#define PGE_WINDOW_IMPLEMENTED 1 +#endif diff --git a/dev/src/api_opengl.cpp b/dev/src/api_opengl.cpp index c1b0b222..c9bf7419 100644 --- a/dev/src/api_opengl.cpp +++ b/dev/src/api_opengl.cpp @@ -19,6 +19,7 @@ namespace olc::apis::opengl bLoaded = true; bLoaded &= (glCreateShader = OGL_LOAD(glCreateShader)) != nullptr; bLoaded &= (glCreateProgram = OGL_LOAD(glCreateProgram)) != nullptr; + bLoaded &= (glShaderSource = OGL_LOAD(glShaderSource)) != nullptr; bLoaded &= (glDeleteShader = OGL_LOAD(glDeleteShader)) != nullptr; bLoaded &= (glCompileShader = OGL_LOAD(glCompileShader)) != nullptr; bLoaded &= (glLinkProgram = OGL_LOAD(glLinkProgram)) != nullptr; @@ -100,5 +101,10 @@ namespace olc::apis::opengl { ::glClearColor(red, green, blue, alpha); } + + void gl::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data) + { + ::glReadPixels(x, y, width, height, format, type, data); + } } //! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/api_opengl.h b/dev/src/api_opengl.h index d7bd033f..df0cd39d 100644 --- a/dev/src/api_opengl.h +++ b/dev/src/api_opengl.h @@ -68,6 +68,7 @@ namespace olc typedef GLuint CALLSTYLE glCreateShader_t(GLenum type); typedef GLuint CALLSTYLE glCreateProgram_t(void); + typedef void CALLSTYLE glShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); typedef void CALLSTYLE glDeleteShader_t(GLuint shader); typedef void CALLSTYLE glCompileShader_t(GLuint shader); typedef void CALLSTYLE glLinkProgram_t(GLuint program); @@ -119,6 +120,7 @@ namespace olc public: glCreateShader_t* glCreateShader = nullptr; glCreateProgram_t* glCreateProgram = nullptr; + glShaderSource_t* glShaderSource = nullptr; glDeleteShader_t* glDeleteShader = nullptr; glCompileShader_t* glCompileShader = nullptr; glLinkProgram_t* glLinkProgram = nullptr; @@ -158,6 +160,7 @@ namespace olc void glClear(GLbitfield mask); void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data); }; } diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index 57199997..cd99a59a 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -129,3 +129,5 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel )); } + +//! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/gpu_iface.cpp b/dev/src/gpu_iface.cpp new file mode 100644 index 00000000..eceba7aa --- /dev/null +++ b/dev/src/gpu_iface.cpp @@ -0,0 +1,37 @@ +#include "gpu_iface.h" + + +//! START IMPLEMENTATION +namespace olc +{ + gpu::Shader::~Shader() + { + } + + void gpu::Shader::SetPixelShaderSource(const std::string& src) + { + srcPixelShader = src; + } + + void gpu::Shader::SetVertexShaderSource(const std::string& src) + { + srcVertexShader = src; + } + + void gpu::Shader::SetGeometryShaderSource(const std::string& src) + { + srcGeometryShader = src; + } + + int32_t gpu::Shader::GetUniform(const std::string& name) const + { + return mapUniforms.at(name); + } + + int32_t gpu::Shader::GetShaderID() const + { + return nCompiledShaderID; + } +} + +//! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/gpu_iface.h b/dev/src/gpu_iface.h index 9d53c82d..054e8a05 100644 --- a/dev/src/gpu_iface.h +++ b/dev/src/gpu_iface.h @@ -34,6 +34,33 @@ namespace olc FailedToSwitchRenderContext, }; + class Shader + { + public: + virtual ~Shader(); + + public: + void SetPixelShaderSource(const std::string& src); + void SetVertexShaderSource(const std::string& src); + void SetGeometryShaderSource(const std::string& src); + + virtual std::string Compile() = 0; + virtual int32_t CreateUniform(const std::string& name) = 0; + + int32_t GetUniform(const std::string& name) const; + int32_t GetShaderID() const; + + protected: + std::string srcPixelShader; + std::string srcVertexShader; + std::string srcGeometryShader; + int32_t nPixelShaderID; + int32_t nVertexShaderID; + int32_t nGeometryShaderID; + int32_t nCompiledShaderID; + std::unordered_map mapUniforms; + }; + class Renderer { public: @@ -67,6 +94,9 @@ namespace olc public: // Shader Construction Stuff + virtual bool ApplyShader(const Shader& shader) = 0; + virtual bool ApplyDefaultShader() = 0; + public: // GPU Task Processing Stuff virtual bool DoGPUTask(const olc::GPUTask& task) = 0; diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index 1eeecc1b..61ebb6ae 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -3,6 +3,61 @@ //! START IMPLEMENTATION namespace olc::gpu { + std::string Shader_GLSL33::Compile() + { + auto& gl = olc::apis::opengl::gl::Get(); + + nCompiledShaderID = gl.glCreateProgram(); + + // Fragment Shader + if (!srcPixelShader.empty()) + { + nPixelShaderID = gl.glCreateShader(0x8B30); + const char* s = srcPixelShader.c_str(); + gl.glShaderSource(nPixelShaderID, 1, &s, nullptr); + gl.glCompileShader(nPixelShaderID); + // TODO: Error Check + gl.glAttachShader(nCompiledShaderID, nPixelShaderID); + } + + // Vertex Shader + if (!srcVertexShader.empty()) + { + nVertexShaderID = gl.glCreateShader(0x8B31); + const char* s = srcVertexShader.c_str(); + gl.glShaderSource(nVertexShaderID, 1, &s, nullptr); + gl.glCompileShader(nVertexShaderID); + // TODO: Error Check + gl.glAttachShader(nCompiledShaderID, nVertexShaderID); + } + + + // Geometry Shader + if (!srcGeometryShader.empty()) + { + nGeometryShaderID = gl.glCreateShader(0x8DD9); + const char* s = srcGeometryShader.c_str(); + gl.glShaderSource(nGeometryShaderID, 1, &s, nullptr); + gl.glCompileShader(nGeometryShaderID); + // TODO: Error Check + gl.glAttachShader(nCompiledShaderID, nGeometryShaderID); + } + + gl.glLinkProgram(nCompiledShaderID); + + return "OK"; + } + + int32_t Shader_GLSL33::CreateUniform(const std::string& name) + { + auto& gl = olc::apis::opengl::gl::Get(); + const char* s = name.c_str(); + mapUniforms.insert({ name, gl.glGetUniformLocation(nCompiledShaderID, s) }); + return GetUniform(name); + } + + + bool Renderer_OGL33::CreateDevice(std::vector params, const RendererConfig& cfg) { config = cfg; @@ -57,6 +112,34 @@ namespace olc::gpu auto& gl = olc::apis::opengl::gl::Get(); + shaderDefault.SetPixelShaderSource( + "#version 330 core\n" + "out vec4 pixel;\n" + "in vec2 oTex;\n" + "in vec4 oCol;\n" + "uniform sampler2D sprTex;\n" + "void main(){pixel = texture(sprTex, oTex) * oCol;}" + ); + + shaderDefault.SetVertexShaderSource( + "#version 330 core\n" + "layout(location = 0) in vec4 aPos;\n" + "layout(location = 1) in vec2 aTex;\n" + "layout(location = 2) in vec4 aCol;\n" + "uniform mat4 mvp;\n" + "uniform int is3d;\n" + "uniform vec4 tint;\n" + "out vec2 oTex;\n" + "out vec4 oCol;\n" + "void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex;} oCol = aCol * tint;}" + ); + + shaderDefault.Compile(); + shaderDefault.CreateUniform("mvp"); + shaderDefault.CreateUniform("is3d"); + shaderDefault.CreateUniform("tint"); + + lastError = RendererError::None; return true; } @@ -114,14 +197,17 @@ namespace olc::gpu bool Renderer_OGL33::WriteTexture(const uint32_t texid, olc::Image& image) { auto& gl = olc::apis::opengl::gl::Get(); + gl.glBindTexture(GL_TEXTURE_2D, image.GetGPUID()); gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.Size().x, image.Size().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); - return false; + return true; } bool Renderer_OGL33::ReadTexture(const uint32_t texid, olc::Image& image) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + gl.glBindTexture(GL_TEXTURE_2D, image.GetGPUID()); + gl.glReadPixels(0, 0, image.Size().x, image.Size().y, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); + return true; } bool Renderer_OGL33::DeleteTexture(const uint32_t texid) @@ -143,10 +229,30 @@ namespace olc::gpu return false; } + bool Renderer_OGL33::ApplyShader(const Shader& shader) + { + auto& gl = olc::apis::opengl::gl::Get(); + gl.glUseProgram(shader.GetShaderID()); + return true; + } + + bool Renderer_OGL33::ApplyDefaultShader() + { + auto& gl = olc::apis::opengl::gl::Get(); + gl.glUseProgram(shaderDefault.GetShaderID()); + return true; + } + bool Renderer_OGL33::DoGPUTask(const olc::GPUTask& task) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + + + + + + + return true; } bool Renderer_OGL33::ClearViewport(const olc::Pixel col, bool bDepth, bool bStencil) @@ -181,5 +287,7 @@ namespace olc::gpu return false; } + + } //! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/gpu_opengl33.h b/dev/src/gpu_opengl33.h index fb18696f..6754d2cd 100644 --- a/dev/src/gpu_opengl33.h +++ b/dev/src/gpu_opengl33.h @@ -9,6 +9,13 @@ namespace olc { namespace gpu { + class Shader_GLSL33 : public olc::gpu::Shader + { + public: + std::string Compile() override; + int32_t CreateUniform(const std::string& name) override; + }; + class Renderer_OGL33 : public olc::gpu::Renderer { public: // Device Stuff @@ -31,6 +38,9 @@ namespace olc // Makes active the given texture resource (for subsequent rendering operations) bool AssignTextureTarget(const uint32_t slot, const uint32_t texid) override; + public: // Shader Construction Stuff + bool ApplyShader(const Shader& shader) override; + bool ApplyDefaultShader() override; public: // GPU Task Stuff virtual bool DoGPUTask(const olc::GPUTask& task) override; @@ -50,6 +60,8 @@ namespace olc olc::apis::opengl::glDeviceContext_t glDeviceContext = 0; olc::apis::opengl::glRenderContext_t glRenderContext = 0; + Shader_GLSL33 shaderDefault; + }; } } diff --git a/dev/src/sh_template.h b/dev/src/sh_template.h index f334ebcd..dc0faf12 100644 --- a/dev/src/sh_template.h +++ b/dev/src/sh_template.h @@ -20,12 +20,14 @@ //! GRAB transform2d.h DECLARATION //! GRAB image.h DECLARATION - -//! GRAB window.h DECLARATION //! GRAB gputask.h DECLARATION //! GRAB gpu_iface.h DECLARATION + +//! GRAB draw2d.h DECLARATION + +//! GRAB window.h DECLARATION //! GRAB host_iface.h DECLARATION @@ -56,10 +58,7 @@ -#if defined(OLC_PGE_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) -//! GRAB window.cpp IMPLEMENTATION -#define PGE_WINDOW_IMPLEMENTED 1 -#endif + #if defined(OLC_PGE_APPLICATION) && !defined(PGE_HOST_IMPLEMENTED) #if OLC_HOST == OLC_HOST_WINDOWS @@ -70,12 +69,18 @@ #if defined(OLC_PGE_APPLICATION) && !defined(PGE_GPU_IMPLEMENTED) #if OLC_GPU == OLC_GPU_OPENGL33 +//! GRAB gpu_iface.cpp IMPLEMENTATION //! GRAB api_opengl.cpp IMPLEMENTATION //! GRAB gpu_opengl33.cpp IMPLEMENTATION #endif #define PGE_GPU_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_DRAW2D_IMPLEMENTED) +//! GRAB draw2d.cpp IMPLEMENTATION +#define PGE_DRAW2D_IMPLEMENTED 1 +#endif + #if defined(OLC_PGE_APPLICATION) && !defined(PGE_CORE_IMPLEMENTED) //! GRAB core.cpp IMPLEMENTATION #define PGE_CORE_IMPLEMENTED 1 @@ -86,4 +91,8 @@ #define PGE_IMAGE_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) +//! GRAB window.cpp IMPLEMENTATION +#define PGE_WINDOW_IMPLEMENTED 1 +#endif diff --git a/dev/src/window.cpp b/dev/src/window.cpp index f6a75ffd..10fc4365 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -94,7 +94,10 @@ namespace olc } } - + // Finialise any outstanding tasks + draw.ProcessGPUTasks(); + + // Update Window's primary surface gpu->DisplayDraw(); return true; From 2c3d28d945153284398acb60d64fb81b102ceeb2 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Sun, 7 Sep 2025 13:38:22 +0100 Subject: [PATCH 03/11] draws a line, albeit clumsily --- dev/src/api_opengl.cpp | 331 ++++++++++++++++++++++++++++++++---- dev/src/api_opengl.h | 117 +++++++++---- dev/src/config.h | 4 + dev/src/core.cpp | 6 +- dev/src/draw2d.cpp | 2 +- dev/src/gpu_iface.h | 2 + dev/src/gpu_opengl33.cpp | 121 ++++++++++++- dev/src/gpu_opengl33.h | 4 + dev/src/gputask.h | 5 + dev/src/host_win_winapi.cpp | 13 +- dev/src/window.cpp | 6 +- dev/tests/test_mh.cpp | 2 +- 12 files changed, 535 insertions(+), 78 deletions(-) diff --git a/dev/src/api_opengl.cpp b/dev/src/api_opengl.cpp index c9bf7419..ee1e5116 100644 --- a/dev/src/api_opengl.cpp +++ b/dev/src/api_opengl.cpp @@ -17,37 +17,37 @@ namespace olc::apis::opengl { // Load all the OpenGL API entry points bLoaded = true; - bLoaded &= (glCreateShader = OGL_LOAD(glCreateShader)) != nullptr; - bLoaded &= (glCreateProgram = OGL_LOAD(glCreateProgram)) != nullptr; - bLoaded &= (glShaderSource = OGL_LOAD(glShaderSource)) != nullptr; - bLoaded &= (glDeleteShader = OGL_LOAD(glDeleteShader)) != nullptr; - bLoaded &= (glCompileShader = OGL_LOAD(glCompileShader)) != nullptr; - bLoaded &= (glLinkProgram = OGL_LOAD(glLinkProgram)) != nullptr; - bLoaded &= (glDeleteProgram = OGL_LOAD(glDeleteProgram)) != nullptr; - bLoaded &= (glAttachShader = OGL_LOAD(glAttachShader)) != nullptr; - bLoaded &= (glBindBuffer = OGL_LOAD(glBindBuffer)) != nullptr; - bLoaded &= (glBufferData = OGL_LOAD(glBufferData)) != nullptr; - bLoaded &= (glGenBuffers = OGL_LOAD(glGenBuffers)) != nullptr; - bLoaded &= (glVertexAttribPointer = OGL_LOAD(glVertexAttribPointer)) != nullptr; - bLoaded &= (glEnableVertexAttribArray = OGL_LOAD(glEnableVertexAttribArray)) != nullptr; - bLoaded &= (glUseProgram = OGL_LOAD(glUseProgram)) != nullptr; - bLoaded &= (glBindVertexArray = OGL_LOAD(glBindVertexArray)) != nullptr; - bLoaded &= (glGenVertexArrays = OGL_LOAD(glGenVertexArrays)) != nullptr; - bLoaded &= (glGetShaderInfoLog = OGL_LOAD(glGetShaderInfoLog)) != nullptr; - bLoaded &= (glGetUniformLocation = OGL_LOAD(glGetUniformLocation)) != nullptr; - bLoaded &= (glUniform1f = OGL_LOAD(glUniform1f)) != nullptr; - bLoaded &= (glUniform1i = OGL_LOAD(glUniform1i)) != nullptr; - bLoaded &= (glUniform2fv = OGL_LOAD(glUniform2fv)) != nullptr; - bLoaded &= (glUniform4fv = OGL_LOAD(glUniform4fv)) != nullptr; - bLoaded &= (glUniformMatrix4fv = OGL_LOAD(glUniformMatrix4fv)) != nullptr; - bLoaded &= (glActiveTexture = OGL_LOAD(glActiveTexture)) != nullptr; - bLoaded &= (glGenFrameBuffers = OGL_LOAD(glGenFrameBuffers)) != nullptr; - bLoaded &= (glBindFrameBuffer = OGL_LOAD(glBindFrameBuffer)) != nullptr; - bLoaded &= (glCheckFrameBufferStatus = OGL_LOAD(glCheckFrameBufferStatus)) != nullptr; - bLoaded &= (glDeleteFrameBuffers = OGL_LOAD(glDeleteFrameBuffers)) != nullptr; - bLoaded &= (glFrameBufferTexture2D = OGL_LOAD(glFrameBufferTexture2D)) != nullptr; - bLoaded &= (glDrawBuffers = OGL_LOAD(glDrawBuffers)) != nullptr; - bLoaded &= (glBlendFuncSeparate = OGL_LOAD(glBlendFuncSeparate)) != nullptr; + bLoaded &= (_glCreateShader = OGL_LOAD(glCreateShader)) != nullptr; + bLoaded &= (_glCreateProgram = OGL_LOAD(glCreateProgram)) != nullptr; + bLoaded &= (_glShaderSource = OGL_LOAD(glShaderSource)) != nullptr; + bLoaded &= (_glDeleteShader = OGL_LOAD(glDeleteShader)) != nullptr; + bLoaded &= (_glCompileShader = OGL_LOAD(glCompileShader)) != nullptr; + bLoaded &= (_glLinkProgram = OGL_LOAD(glLinkProgram)) != nullptr; + bLoaded &= (_glDeleteProgram = OGL_LOAD(glDeleteProgram)) != nullptr; + bLoaded &= (_glAttachShader = OGL_LOAD(glAttachShader)) != nullptr; + bLoaded &= (_glBindBuffer = OGL_LOAD(glBindBuffer)) != nullptr; + bLoaded &= (_glBufferData = OGL_LOAD(glBufferData)) != nullptr; + bLoaded &= (_glGenBuffers = OGL_LOAD(glGenBuffers)) != nullptr; + bLoaded &= (_glVertexAttribPointer = OGL_LOAD(glVertexAttribPointer)) != nullptr; + bLoaded &= (_glEnableVertexAttribArray = OGL_LOAD(glEnableVertexAttribArray)) != nullptr; + bLoaded &= (_glUseProgram = OGL_LOAD(glUseProgram)) != nullptr; + bLoaded &= (_glBindVertexArray = OGL_LOAD(glBindVertexArray)) != nullptr; + bLoaded &= (_glGenVertexArrays = OGL_LOAD(glGenVertexArrays)) != nullptr; + bLoaded &= (_glGetShaderInfoLog = OGL_LOAD(glGetShaderInfoLog)) != nullptr; + bLoaded &= (_glGetUniformLocation = OGL_LOAD(glGetUniformLocation)) != nullptr; + bLoaded &= (_glUniform1f = OGL_LOAD(glUniform1f)) != nullptr; + bLoaded &= (_glUniform1i = OGL_LOAD(glUniform1i)) != nullptr; + bLoaded &= (_glUniform2fv = OGL_LOAD(glUniform2fv)) != nullptr; + bLoaded &= (_glUniform4fv = OGL_LOAD(glUniform4fv)) != nullptr; + bLoaded &= (_glUniformMatrix4fv = OGL_LOAD(glUniformMatrix4fv)) != nullptr; + bLoaded &= (_glActiveTexture = OGL_LOAD(glActiveTexture)) != nullptr; + bLoaded &= (_glGenFrameBuffers = OGL_LOAD(glGenFrameBuffers)) != nullptr; + bLoaded &= (_glBindFrameBuffer = OGL_LOAD(glBindFrameBuffer)) != nullptr; + bLoaded &= (_glCheckFrameBufferStatus = OGL_LOAD(glCheckFrameBufferStatus)) != nullptr; + bLoaded &= (_glDeleteFrameBuffers = OGL_LOAD(glDeleteFrameBuffers)) != nullptr; + bLoaded &= (_glFrameBufferTexture2D = OGL_LOAD(glFrameBufferTexture2D)) != nullptr; + bLoaded &= (_glDrawBuffers = OGL_LOAD(glDrawBuffers)) != nullptr; + bLoaded &= (_glBlendFuncSeparate = OGL_LOAD(glBlendFuncSeparate)) != nullptr; if (!bLoaded) return false; // API load has failed @@ -57,54 +57,323 @@ namespace olc::apis::opengl return bLoaded; } + bool gl::CheckError(const std::source_location loc) + { +#if OLC_GPU_ERRORCHECK == 1 + GLenum err; + bool bWasError = false; + std::stringstream sLocation; + sLocation + << loc.file_name() << '(' + << loc.line() << ':' + << loc.column() << ") `" + << loc.function_name() << "`: "; + while ((err = ::glGetError()) != GL_NO_ERROR) + { + switch (err) + { + case GL_INVALID_ENUM: + sLocation << "OGL33 Error: GL_INVALID_ENUM\n"; break; + case GL_INVALID_VALUE: + sLocation << "OGL33 Error: GL_INVALID_VALUE\n"; break; + case GL_INVALID_OPERATION: + sLocation << "OGL33 Error: GL_INVALID_OPERATION\n"; break; + case 0x0506: //GL_INVALID_FRAMEBUFFER_OPERATION: + sLocation << "OGL33 Error: GL_INVALID_FRAMEBUFFER_OPERATION\n"; break; + case GL_OUT_OF_MEMORY: + sLocation << "OGL33 Error: GL_OUT_OF_MEMORY\n"; break; + case GL_STACK_UNDERFLOW: + sLocation << "OGL33 Error: GL_STACK_UNDERFLOW\n"; break; + case GL_STACK_OVERFLOW: + sLocation << "OGL33 Error: GL_STACK_OVERFLOW\n"; break; + } + bWasError = true; + + std::cout << sLocation.str() << "\n"; + sLocation.clear(); + } + return bWasError; +#else + return false; +#endif + } + void gl::glGenTextures(GLsizei n, GLuint* textures) { ::glGenTextures(n, textures); + CheckError(); } void gl::glBindTexture(GLenum target, GLuint texture) { ::glBindTexture(target, texture); + CheckError(); } void gl::glTexParameteri(GLenum target, GLenum pname, GLint param) { ::glTexParameteri(target, pname, param); + CheckError(); } void gl::glTexEnvf(GLenum target, GLenum pname, GLfloat param) { ::glTexEnvf(target, pname, param); + CheckError(); } void gl::glDeleteTextures(GLsizei n, const GLuint* textures) { ::glDeleteTextures(n, textures); + CheckError(); } void gl::glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + CheckError(); } void gl::glClear(GLbitfield mask) { ::glClear(mask); + CheckError(); } void gl::glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { ::glViewport(x, y, width, height); + CheckError(); } void gl::glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { ::glClearColor(red, green, blue, alpha); + CheckError(); } void gl::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data) { ::glReadPixels(x, y, width, height, format, type, data); + CheckError(); + } + + void gl::glCullFace(GLenum mode) + { + ::glCullFace(mode); + CheckError(); + } + + void gl::glEnable(GLenum cap) + { + ::glEnable(cap); + CheckError(); + } + + void gl::glDisable(GLenum cap) + { + ::glDisable(cap); + CheckError(); + } + + void gl::glDrawArrays(GLenum mode, GLint first, GLsizei count) + { + ::glDrawArrays(mode, first, count); + CheckError(); + } + + void gl::glBlendFunc(GLenum sfactor, GLenum dfactor) + { + ::glBlendFunc(sfactor, dfactor); + CheckError(); + } + + void gl::glDepthFunc(GLenum func) + { + ::glDepthFunc(func); + CheckError(); + } + + GLuint gl::glCreateShader(GLenum type) + { + return _glCreateShader(type); + } + + GLuint gl::glCreateProgram(void) + { + return _glCreateProgram(); + } + + void gl::glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) + { + _glShaderSource(shader, count, string, length); + CheckError(); + } + + void gl::glDeleteShader(GLuint shader) + { + _glDeleteShader(shader); + CheckError(); + } + + void gl::glCompileShader(GLuint shader) + { + _glCompileShader(shader); + CheckError(); + } + + void gl::glLinkProgram(GLuint program) + { + _glLinkProgram(program); + CheckError(); + } + + void gl::glDeleteProgram(GLuint program) + { + _glDeleteProgram(program); + CheckError(); + } + + void gl::glAttachShader(GLuint program, GLuint shader) + { + _glAttachShader(program, shader); + CheckError(); + } + + void gl::glBindBuffer(GLenum target, GLuint buffer) + { + _glBindBuffer(target, buffer); + CheckError(); + } + + void gl::glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) + { + _glBufferData(target, size, data, usage); + CheckError(); + } + + void gl::glGenBuffers(GLsizei n, GLuint* buffers) + { + _glGenBuffers(n, buffers); + CheckError(); + } + + void gl::glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) + { + _glVertexAttribPointer(index, size, type, normalized, stride, pointer); + CheckError(); + } + + void gl::glEnableVertexAttribArray(GLuint index) + { + _glEnableVertexAttribArray(index); + CheckError(); + } + + void gl::glUseProgram(GLuint program) + { + _glUseProgram(program); + CheckError(); + } + + void gl::glBindVertexArray(GLuint array) + { + _glBindVertexArray(array); + CheckError(); + } + + void gl::glGenVertexArrays(GLsizei n, GLuint* arrays) + { + _glGenVertexArrays(n, arrays); + CheckError(); + } + + void gl::glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) + { + _glGetShaderInfoLog(shader, bufSize, length, infoLog); + CheckError(); + } + + GLint gl::glGetUniformLocation(GLuint program, const GLchar* name) + { + return _glGetUniformLocation(program, name); + } + + void gl::glUniform1f(GLint location, GLfloat v0) + { + _glUniform1f(location, v0); + CheckError(); + } + + void gl::glUniform1i(GLint location, GLint v0) + { + _glUniform1i(location, v0); + CheckError(); + } + + void gl::glUniform2fv(GLint location, GLsizei count, const GLfloat* value) + { + _glUniform2fv(location, count, value); + CheckError(); + } + + void gl::glUniform4fv(GLint location, GLsizei count, const GLfloat* value) + { + _glUniform4fv(location, count, value); + CheckError(); + } + + void gl::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value) + { + _glUniformMatrix4fv(location, count, trasnpose, value); + CheckError(); + } + + void gl::glActiveTexture(GLenum texture) + { + _glActiveTexture(texture); + CheckError(); + } + + void gl::glGenFrameBuffers(GLsizei n, GLuint* ids) + { + _glGenFrameBuffers(n, ids); + CheckError(); + } + + void gl::glBindFrameBuffer(GLenum target, GLuint fb) + { + _glBindFrameBuffer(target, fb); + CheckError(); + } + + GLenum gl::glCheckFrameBufferStatus(GLenum target) + { + return _glCheckFrameBufferStatus(target); + } + + void gl::glDeleteFrameBuffers(GLsizei n, const GLuint* fbs) + { + _glDeleteFrameBuffers(n, fbs); + CheckError(); + } + + void gl::glFrameBufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + { + _glFrameBufferTexture2D(target, attachment, textarget, texture, level); + CheckError(); + } + + void gl::glDrawBuffers(GLsizei n, const GLenum* bufs) + { + _glDrawBuffers(n, bufs); + CheckError(); + } + + void gl::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + { + _glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + CheckError(); } } //! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/api_opengl.h b/dev/src/api_opengl.h index df0cd39d..b1b65a2f 100644 --- a/dev/src/api_opengl.h +++ b/dev/src/api_opengl.h @@ -3,8 +3,15 @@ //! START CUSTOMHEADER #include "config.h" + //! END CUSTOMHEADER +//! START STDHEADER GLOBAL +#include +#include +#include +//! END STDHEADER + //! START OPENGL_CONFIG @@ -117,38 +124,75 @@ namespace olc private: bool LoadAll(); + protected: + glCreateShader_t* _glCreateShader = nullptr; + glCreateProgram_t* _glCreateProgram = nullptr; + glShaderSource_t* _glShaderSource = nullptr; + glDeleteShader_t* _glDeleteShader = nullptr; + glCompileShader_t* _glCompileShader = nullptr; + glLinkProgram_t* _glLinkProgram = nullptr; + glDeleteProgram_t* _glDeleteProgram = nullptr; + glAttachShader_t* _glAttachShader = nullptr; + glBindBuffer_t* _glBindBuffer = nullptr; + glBufferData_t* _glBufferData = nullptr; + glGenBuffers_t* _glGenBuffers = nullptr; + glVertexAttribPointer_t* _glVertexAttribPointer = nullptr; + glEnableVertexAttribArray_t* _glEnableVertexAttribArray = nullptr; + glUseProgram_t* _glUseProgram = nullptr; + glBindVertexArray_t* _glBindVertexArray = nullptr; + glGenVertexArrays_t* _glGenVertexArrays = nullptr; + glGetShaderInfoLog_t* _glGetShaderInfoLog = nullptr; + glGetUniformLocation_t* _glGetUniformLocation = nullptr; + glUniform1f_t* _glUniform1f = nullptr; + glUniform1i_t* _glUniform1i = nullptr; + glUniform2fv_t* _glUniform2fv = nullptr; + glUniform4fv_t* _glUniform4fv = nullptr; + glUniformMatrix4fv_t* _glUniformMatrix4fv = nullptr; + glActiveTexture_t* _glActiveTexture = nullptr; + glGenFrameBuffers_t* _glGenFrameBuffers = nullptr; + glBindFrameBuffer_t* _glBindFrameBuffer = nullptr; + glCheckFrameBufferStatus_t* _glCheckFrameBufferStatus = nullptr; + glDeleteFrameBuffers_t* _glDeleteFrameBuffers = nullptr; + glFrameBufferTexture2D_t* _glFrameBufferTexture2D = nullptr; + glDrawBuffers_t* _glDrawBuffers = nullptr; + glBlendFuncSeparate_t* _glBlendFuncSeparate = nullptr; + public: - glCreateShader_t* glCreateShader = nullptr; - glCreateProgram_t* glCreateProgram = nullptr; - glShaderSource_t* glShaderSource = nullptr; - glDeleteShader_t* glDeleteShader = nullptr; - glCompileShader_t* glCompileShader = nullptr; - glLinkProgram_t* glLinkProgram = nullptr; - glDeleteProgram_t* glDeleteProgram = nullptr; - glAttachShader_t* glAttachShader = nullptr; - glBindBuffer_t* glBindBuffer = nullptr; - glBufferData_t* glBufferData = nullptr; - glGenBuffers_t* glGenBuffers = nullptr; - glVertexAttribPointer_t* glVertexAttribPointer = nullptr; - glEnableVertexAttribArray_t* glEnableVertexAttribArray = nullptr; - glUseProgram_t* glUseProgram = nullptr; - glBindVertexArray_t* glBindVertexArray = nullptr; - glGenVertexArrays_t* glGenVertexArrays = nullptr; - glGetShaderInfoLog_t* glGetShaderInfoLog = nullptr; - glGetUniformLocation_t* glGetUniformLocation = nullptr; - glUniform1f_t* glUniform1f = nullptr; - glUniform1i_t* glUniform1i = nullptr; - glUniform2fv_t* glUniform2fv = nullptr; - glUniform4fv_t* glUniform4fv = nullptr; - glUniformMatrix4fv_t* glUniformMatrix4fv = nullptr; - glActiveTexture_t* glActiveTexture = nullptr; - glGenFrameBuffers_t* glGenFrameBuffers = nullptr; - glBindFrameBuffer_t* glBindFrameBuffer = nullptr; - glCheckFrameBufferStatus_t* glCheckFrameBufferStatus = nullptr; - glDeleteFrameBuffers_t* glDeleteFrameBuffers = nullptr; - glFrameBufferTexture2D_t* glFrameBufferTexture2D = nullptr; - glDrawBuffers_t* glDrawBuffers = nullptr; - glBlendFuncSeparate_t* glBlendFuncSeparate = nullptr; + // Proxies allow switchable, clutter-free error checking + + // OpenGL3.3 Proxies + + GLuint glCreateShader(GLenum type); + GLuint glCreateProgram(void); + void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); + void glDeleteShader(GLuint shader); + void glCompileShader(GLuint shader); + void glLinkProgram(GLuint program); + void glDeleteProgram(GLuint program); + void glAttachShader(GLuint program, GLuint shader); + void glBindBuffer(GLenum target, GLuint buffer); + void glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + void glGenBuffers(GLsizei n, GLuint* buffers); + void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); + void glEnableVertexAttribArray(GLuint index); + void glUseProgram(GLuint program); + void glBindVertexArray(GLuint array); + void glGenVertexArrays(GLsizei n, GLuint* arrays); + void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); + GLint glGetUniformLocation(GLuint program, const GLchar* name); + void glUniform1f(GLint location, GLfloat v0); + void glUniform1i(GLint location, GLint v0); + void glUniform2fv(GLint location, GLsizei count, const GLfloat* value); + void glUniform4fv(GLint location, GLsizei count, const GLfloat* value); + void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value); + void glActiveTexture(GLenum texture); + void glGenFrameBuffers(GLsizei n, GLuint* ids); + void glBindFrameBuffer(GLenum target, GLuint fb); + GLenum glCheckFrameBufferStatus(GLenum target); + void glDeleteFrameBuffers(GLsizei n, const GLuint* fbs); + void glFrameBufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void glDrawBuffers(GLsizei n, const GLenum* bufs); + void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); // OpenGL1.2 Proxies (just keeps things tidy imo) void glGenTextures(GLsizei n, GLuint* textures); @@ -161,6 +205,17 @@ namespace olc void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data); + void glCullFace(GLenum mode); + void glEnable(GLenum cap); + void glDisable(GLenum cap); + void glDrawArrays(GLenum mode, GLint first, GLsizei count); + void glBlendFunc(GLenum sfactor, GLenum dfactor); + void glDepthFunc(GLenum func); + + + + private: + bool CheckError(const std::source_location loc = std::source_location::current()); }; } diff --git a/dev/src/config.h b/dev/src/config.h index bac80e0f..44a75708 100644 --- a/dev/src/config.h +++ b/dev/src/config.h @@ -70,6 +70,10 @@ #define OLC_GPU OLC_GPU_OPENGL33 #endif + +#define OLC_GPU_MAX_VERTICES 8192 +#define OLC_GPU_ERRORCHECK 1 + #define LICENCE_DEFAULT "OneLoneCoder.com - Pixel Game Engine 3 - " //! END CONFIGURATION \ No newline at end of file diff --git a/dev/src/core.cpp b/dev/src/core.cpp index 0e8b95bd..8e515a51 100644 --- a/dev/src/core.cpp +++ b/dev/src/core.cpp @@ -38,7 +38,7 @@ namespace olc // Link this olc::Window to a host resource if (host) - host->AddWindowFrame(this, { 30,30 }, { 250, 240 }, false); + host->AddWindowFrame(this, { 30,30 }, config.vPixelSize * config.vScreenSize, false); coreActive = true; coreThread = std::thread(&PixelGameEngine::EngineThread, this); @@ -149,7 +149,7 @@ namespace olc } - CreateImage(imgPrimary, GetSize()); + CreateImage(imgPrimary, { 200, 200 }); if (!OnUserCreate()) { @@ -206,7 +206,7 @@ namespace olc // Wait for vertical sync if required. // Note: Child windows will never vsync as waiting for each buffer swap with vsync - // divides up teh frame rate budget across the windows. + // divides up the frame rate budget across the windows. if (gpu->GetConfig().VerticalSync) { host->SyncWithDesktopComposite(); diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index cd99a59a..eae3202c 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -85,7 +85,7 @@ GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::ve GPUTask task; task.bWireframe = true; for (const auto& v : vPoints) - task.vertexBuffer.push_back({ v.x, v.y, 0.0f, 0.0f, 0.0f, 0.0f, colour }); + task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, 0.0f, 0.0f, colour }); task.tint = tint; return task; } diff --git a/dev/src/gpu_iface.h b/dev/src/gpu_iface.h index 054e8a05..edf28e45 100644 --- a/dev/src/gpu_iface.h +++ b/dev/src/gpu_iface.h @@ -72,6 +72,8 @@ namespace olc inline RendererError GetLastError() const { return lastError; } inline const RendererConfig& GetConfig() const { return config; } + + public: // Device Stuff // Constructs a GPU Device interface virtual bool CreateDevice(std::vector params, const RendererConfig& cfg) = 0; diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index 61ebb6ae..f85707a3 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -111,7 +111,7 @@ namespace olc::gpu // Can't load OpenGL API until context is loaded auto& gl = olc::apis::opengl::gl::Get(); - + // Create "Default" Shader shaderDefault.SetPixelShaderSource( "#version 330 core\n" "out vec4 pixel;\n" @@ -139,6 +139,44 @@ namespace olc::gpu shaderDefault.CreateUniform("is3d"); shaderDefault.CreateUniform("tint"); + // Create "Default" Vertex Buffer / Vertex Attributes. This buffer is reused + // for all drawing operations. It's possible future versions may allow the + // creation of additional named buffers for repeated drawing operations with + // minimal overhead. + gl.glGenBuffers(1, &nDefaultVB); + gl.glGenVertexArrays(1, &nDefaultVA); + gl.glBindVertexArray(nDefaultVA); + gl.glBindBuffer(0x8892, nDefaultVB); + + // A big one is allocated to reduce shuffles in GPU memory + GPUTask::Vertex verts[OLC_GPU_MAX_VERTICES]; + gl.glBufferData(0x8892, sizeof(GPUTask::Vertex) * OLC_GPU_MAX_VERTICES, verts, 0x88E0); + + // Float Index 0 = x, 1 = y, 2 = z, 3 = w + gl.glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(0 * sizeof(float))); + gl.glEnableVertexAttribArray(0); + // Float Index 4 = u, 5 = v + gl.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(4 * sizeof(float))); + gl.glEnableVertexAttribArray(1); + // Float Index 6 = (RGBA 8-bit x4) + gl.glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GPUTask::Vertex), (void*)(6 * sizeof(float))); + gl.glEnableVertexAttribArray(2); + + // Buffers are configured, unbind for now + gl.glBindBuffer(0x8892, 0); + gl.glBindVertexArray(0); + + + // Create a null-texture so sampler doesnt fail. We don't have some of the core's helper + // functions here, so we construct it manually + imgBlank.Create({ 1,1 }); + imgBlank.SetGPUID(CreateTexture(imgBlank.Size())); + imgBlank.BindCPU(); + imgBlank.Data({ 0,0 }) = olc::Colour::WHITE; + imgBlank.BindGPU(); + WriteTexture(imgBlank.GetGPUID(), imgBlank); + + lastError = RendererError::None; return true; @@ -247,10 +285,81 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); - - - - + switch (task.task) + { + case GPUTask::Task::DrawPolygon: + { + gl.glUseProgram(shaderDefault.GetShaderID()); + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl.glDepthFunc(GL_LESS); + gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); + + // Bind generic vertex buffer + gl.glBindVertexArray(nDefaultVA); + gl.glBindBuffer(0x8892, nDefaultVB); + + // Copy data from CPU to GPU + gl.glBufferData(0x8892, sizeof(GPUTask::Vertex) * task.vertexBuffer.size(), task.vertexBuffer.data(), 0x88E0); + + // Shader: Configure Rendering Mode + gl.glUniform1i(shaderDefault.GetUniform("is3d"), 0); + + // Shader: Apply MVP Matrix + gl.glUniformMatrix4fv(shaderDefault.GetUniform("mvp"), 1, false, task.mvpMatrix.data()); + + // Shader: Apply Global Tint + float f[4] = { + float(task.tint.r) / 255.0f, + float(task.tint.g) / 255.0f, + float(task.tint.b) / 255.0f, + float(task.tint.a) / 255.0f + }; + gl.glUniform4fv(shaderDefault.GetUniform("tint"), 1, f); + + // Apply Culling modes + if (task.cullmode == GPUTask::CullMode::None) + { + gl.glCullFace(GL_FRONT); + gl.glDisable(GL_CULL_FACE); + } + else if (task.cullmode == GPUTask::CullMode::ClockWise) + { + gl.glCullFace(GL_FRONT); + gl.glEnable(GL_CULL_FACE); + } + else if (task.cullmode == GPUTask::CullMode::CounterClockWise) + { + gl.glCullFace(GL_BACK); + gl.glEnable(GL_CULL_FACE); + } + + // Apply Depth Testing (if required) + if (task.bDepth) + gl.glEnable(GL_DEPTH_TEST); + + // Draw the thing! + if (task.bWireframe) + { + gl.glDrawArrays(GL_LINE_LOOP, 0, (GLsizei)task.vertexBuffer.size()); + } + else + { + if (task.structure == GPUTask::Structure::Fan) + gl.glDrawArrays(GL_TRIANGLE_FAN, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::Strip) + gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::List) + gl.glDrawArrays(GL_TRIANGLES, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::Line) + gl.glDrawArrays(GL_LINES, 0, (GLsizei)task.vertexBuffer.size()); + } + + if (task.bDepth) + gl.glDisable(GL_DEPTH_TEST); + + } + break; + } return true; } @@ -267,7 +376,7 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); gl.glViewport(int(pos.x), int(pos.y), int(size.x), int(size.y)); - return false; + return true; } bool Renderer_OGL33::DisplayPrepare() diff --git a/dev/src/gpu_opengl33.h b/dev/src/gpu_opengl33.h index 6754d2cd..8ed63db6 100644 --- a/dev/src/gpu_opengl33.h +++ b/dev/src/gpu_opengl33.h @@ -24,6 +24,7 @@ namespace olc // Destroys a GPU device interface bool DestroyDevice() override; + public: // Texture Resource Stuff // Allocates a new texture resource in VRAM, returns handle uint32_t CreateTexture(const olc::vi2d& vSize, const olc::ImageConfig& cfg = olc::ImageConfig()) override; @@ -61,6 +62,9 @@ namespace olc olc::apis::opengl::glRenderContext_t glRenderContext = 0; Shader_GLSL33 shaderDefault; + uint32_t nDefaultVB = 0; + uint32_t nDefaultVA = 0; + olc::Image imgBlank; }; } diff --git a/dev/src/gputask.h b/dev/src/gputask.h index 3310d4d1..dc863458 100644 --- a/dev/src/gputask.h +++ b/dev/src/gputask.h @@ -26,6 +26,11 @@ namespace olc // upon PGE structures struct GPUTask { + enum class Task : uint8_t + { + DrawPolygon, + } task = Task::DrawPolygon; + struct Vertex { float p[6]; // x, y, z, w, u, v diff --git a/dev/src/host_win_winapi.cpp b/dev/src/host_win_winapi.cpp index dad6a113..06be24e8 100644 --- a/dev/src/host_win_winapi.cpp +++ b/dev/src/host_win_winapi.cpp @@ -68,8 +68,9 @@ namespace olc::host { // The user created olc::Window object is the SSoT for what a window // should look like, so get that sort of thing from there - olc::vi2d vWinPos = pWindow->GetPosition(); - olc::vi2d vWinSize = pWindow->GetSize(); + olc::vi2d vWinPos = vWindowPos; + olc::vi2d vWinSize = vWindowSize; + // Define WindowClass WNDCLASS wc = { 0 }; @@ -109,6 +110,7 @@ namespace olc::host AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); int width = rWndRect.right - rWndRect.left; int height = rWndRect.bottom - rWndRect.top; + pWindow->SetSize({width, height}); // Create the actual OS window, return a handle HWND hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE3"), olcT(""), dwStyle, @@ -187,7 +189,12 @@ namespace olc::host // case WM_MOVE: vWinPos = olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); ptrPGE->olc_UpdateWindowPos(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0; - // case WM_SIZE: vWinSize = olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); ptrPGE->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0; + case WM_SIZE: + { + window->olc_OnWindowSize(olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF)); + return 0; + } + break; // case WM_MOUSEWHEEL: ptrPGE->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); return 0; // case WM_MOUSELEAVE: ptrPGE->olc_UpdateMouseFocus(false); return 0; // case WM_SETFOCUS: ptrPGE->olc_UpdateKeyFocus(true); return 0; diff --git a/dev/src/window.cpp b/dev/src/window.cpp index 10fc4365..b7528452 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -64,7 +64,7 @@ namespace olc bool Window::olc_OnWindowSize(const olc::vi2d& vWindowSize) { - return false; + return SetSize(vWindowSize); } bool Window::olc_ShouldRemove() const @@ -80,8 +80,10 @@ namespace olc draw.SetGPU(gpu); draw.SetTarget(imgPrimary); + gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::TANGERINE, false, false); + gpu->ClearViewport(olc::Colour::TANGERINE, true, true); + gpu->ApplyDefaultShader(); // User Update if (!OnUserUpdate(fElapsedTime)) diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index 8074dd17..31b8f55c 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -20,7 +20,7 @@ class Example : public olc::PixelGameEngine bool OnUserUpdate(float fElapsedTime) override { - draw.Line({ 10,10 }, { 20,20 }, olc::Colour::BLUE); + draw.Line({ 0,0 }, { 200,200 }, olc::Colour::WHITE); return true; } From 85f4cf5bf3925c8aef337f62fd4382282dea2269 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Sun, 7 Sep 2025 13:47:32 +0100 Subject: [PATCH 04/11] Fixed colour discrepency --- dev/src/config.h | 2 +- dev/src/gpu_opengl33.cpp | 11 ++++++----- dev/src/window.cpp | 3 ++- dev/tests/test_mh.cpp | 5 ++++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dev/src/config.h b/dev/src/config.h index 44a75708..3dafb34d 100644 --- a/dev/src/config.h +++ b/dev/src/config.h @@ -11,7 +11,7 @@ #define PGE_PIXEL_LAYOUT_ABGR 2 #if !defined(PGE_PIXEL_LAYOUT) - #define PGE_PIXEL_LAYOUT PGE_PIXEL_LAYOUT_ABGR + #define PGE_PIXEL_LAYOUT PGE_PIXEL_LAYOUT_RGBA #endif diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index f85707a3..b9e92479 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -289,11 +289,6 @@ namespace olc::gpu { case GPUTask::Task::DrawPolygon: { - gl.glUseProgram(shaderDefault.GetShaderID()); - gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl.glDepthFunc(GL_LESS); - gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); - // Bind generic vertex buffer gl.glBindVertexArray(nDefaultVA); gl.glBindBuffer(0x8892, nDefaultVB); @@ -382,6 +377,12 @@ namespace olc::gpu bool Renderer_OGL33::DisplayPrepare() { auto& gl = olc::apis::opengl::gl::Get(); + + //gl.glUseProgram(shaderDefault.GetShaderID()); + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl.glDepthFunc(GL_LESS); + gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); + return false; } diff --git a/dev/src/window.cpp b/dev/src/window.cpp index b7528452..af62fdb9 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -81,8 +81,9 @@ namespace olc draw.SetTarget(imgPrimary); + gpu->DisplayPrepare(); gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::TANGERINE, true, true); + gpu->ClearViewport(olc::Colour::BLACK, true, true); gpu->ApplyDefaultShader(); // User Update diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index 31b8f55c..bc2eb9e8 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -20,7 +20,10 @@ class Example : public olc::PixelGameEngine bool OnUserUpdate(float fElapsedTime) override { - draw.Line({ 0,0 }, { 200,200 }, olc::Colour::WHITE); + draw.Line({ 0,0 }, { 1, 1 }, olc::Colour::RED); + draw.Line({ 0,0 }, { 1, -1 }, olc::Colour::GREEN); + draw.Line({ 0,0 }, { -1, -1 }, olc::Colour::BLUE); + draw.Line({ 0,0 }, { -1, 1 }, olc::Colour::WHITE); return true; } From 8014c96051ed273b3377b3cbcd41986993708742 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Sun, 7 Sep 2025 21:35:43 +0100 Subject: [PATCH 05/11] Can draw pixels at last! Uses hardware to draw almost everything. System silently switches between software/hardware when required. --- .../olcPGE3_BuildSH/olcPixelGameEngine3.h | 766 +++++++++++++++--- dev/msvc/olcPGE3_BuildSH/test_sh.cpp | 12 + dev/src/api_opengl.cpp | 37 +- dev/src/api_opengl.h | 31 +- dev/src/core.cpp | 3 +- dev/src/draw2d.cpp | 46 +- dev/src/draw2d.h | 7 + dev/src/gpu_opengl33.cpp | 79 +- dev/src/gpu_opengl33.h | 1 + dev/src/gputask.h | 9 +- dev/src/window.cpp | 14 +- dev/tests/test_mh.cpp | 10 +- 12 files changed, 861 insertions(+), 154 deletions(-) diff --git a/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h b/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h index f6c6e24d..c9f16ddf 100644 --- a/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h +++ b/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include // Version number (accessible as value for incremental comparisons) #define PGE_VER 300 @@ -32,7 +34,7 @@ #define PGE_PIXEL_LAYOUT_ABGR 2 #if !defined(PGE_PIXEL_LAYOUT) - #define PGE_PIXEL_LAYOUT PGE_PIXEL_LAYOUT_ABGR + #define PGE_PIXEL_LAYOUT PGE_PIXEL_LAYOUT_RGBA #endif @@ -91,6 +93,10 @@ #define OLC_GPU OLC_GPU_OPENGL33 #endif + +#define OLC_GPU_MAX_VERTICES 8192 +#define OLC_GPU_ERRORCHECK 1 + #define LICENCE_DEFAULT "OneLoneCoder.com - Pixel Game Engine 3 - " @@ -1182,10 +1188,19 @@ namespace olc // upon PGE structures struct GPUTask { + enum class Task : uint8_t + { + DrawPolygon, + } task = Task::DrawPolygon; + struct Vertex { - float p[6]; // x, y, z, w, u, v + float p[4]; // x, y, z, w olc::Pixel c; // 32-bit colour + float t0[2]; + float t1[2]; + float t2[2]; + float t3[2]; }; // Simple vertex buffer @@ -1208,6 +1223,8 @@ namespace olc // Overall biasing colour (great for blends) olc::Pixel tint = olc::Colour::WHITE; + olc::Image* pImage = nullptr; + // Define super structure to be drawn enum class Structure : uint8_t { @@ -1333,6 +1350,8 @@ namespace olc inline RendererError GetLastError() const { return lastError; } inline const RendererConfig& GetConfig() const { return config; } + + public: // Device Stuff // Constructs a GPU Device interface virtual bool CreateDevice(std::vector params, const RendererConfig& cfg) = 0; @@ -1455,6 +1474,7 @@ namespace olc GPUTask TaskTexturedPolygon( GPUTask::Structure structure, + const std::vector& vPoints, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, @@ -1467,6 +1487,12 @@ namespace olc GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); // Draws a single pixel wide line with a gradient GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + + // Draws a filled, single colour rectangle + GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + + // Draws a filled, single colour rectangle + GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); }; } #define PGE_DRAW2D_DECLARED @@ -1887,11 +1913,11 @@ namespace olc typedef void CALLSTYLE glUniform4fv_t(GLint location, GLsizei count, const GLfloat* value); typedef void CALLSTYLE glUniformMatrix4fv_t(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value); typedef void CALLSTYLE glActiveTexture_t(GLenum texture); - typedef void CALLSTYLE glGenFrameBuffers_t(GLsizei n, GLuint* ids); - typedef void CALLSTYLE glBindFrameBuffer_t(GLenum target, GLuint fb); - typedef GLenum CALLSTYLE glCheckFrameBufferStatus_t(GLenum target); - typedef void CALLSTYLE glDeleteFrameBuffers_t(GLsizei n, const GLuint* fbs); - typedef void CALLSTYLE glFrameBufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + typedef void CALLSTYLE glGenFramebuffers_t(GLsizei n, GLuint* ids); + typedef void CALLSTYLE glBindFramebuffer_t(GLenum target, GLuint fb); + typedef GLenum CALLSTYLE glCheckFramebufferStatus_t(GLenum target); + typedef void CALLSTYLE glDeleteFramebuffers_t(GLsizei n, const GLuint* fbs); + typedef void CALLSTYLE glFramebufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void CALLSTYLE glDrawBuffers_t(GLsizei n, const GLenum* bufs); typedef void CALLSTYLE glBlendFuncSeparate_t(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); @@ -1906,6 +1932,7 @@ namespace olc { public: static gl& Get(); + inline bool HasLoaded() const { return bLoaded; } private: gl() = default; @@ -1914,38 +1941,75 @@ namespace olc private: bool LoadAll(); + protected: + glCreateShader_t* _glCreateShader = nullptr; + glCreateProgram_t* _glCreateProgram = nullptr; + glShaderSource_t* _glShaderSource = nullptr; + glDeleteShader_t* _glDeleteShader = nullptr; + glCompileShader_t* _glCompileShader = nullptr; + glLinkProgram_t* _glLinkProgram = nullptr; + glDeleteProgram_t* _glDeleteProgram = nullptr; + glAttachShader_t* _glAttachShader = nullptr; + glBindBuffer_t* _glBindBuffer = nullptr; + glBufferData_t* _glBufferData = nullptr; + glGenBuffers_t* _glGenBuffers = nullptr; + glVertexAttribPointer_t* _glVertexAttribPointer = nullptr; + glEnableVertexAttribArray_t* _glEnableVertexAttribArray = nullptr; + glUseProgram_t* _glUseProgram = nullptr; + glBindVertexArray_t* _glBindVertexArray = nullptr; + glGenVertexArrays_t* _glGenVertexArrays = nullptr; + glGetShaderInfoLog_t* _glGetShaderInfoLog = nullptr; + glGetUniformLocation_t* _glGetUniformLocation = nullptr; + glUniform1f_t* _glUniform1f = nullptr; + glUniform1i_t* _glUniform1i = nullptr; + glUniform2fv_t* _glUniform2fv = nullptr; + glUniform4fv_t* _glUniform4fv = nullptr; + glUniformMatrix4fv_t* _glUniformMatrix4fv = nullptr; + glActiveTexture_t* _glActiveTexture = nullptr; + glGenFramebuffers_t* _glGenFramebuffers = nullptr; + glBindFramebuffer_t* _glBindFramebuffer = nullptr; + glCheckFramebufferStatus_t* _glCheckFramebufferStatus = nullptr; + glDeleteFramebuffers_t* _glDeleteFramebuffers = nullptr; + glFramebufferTexture2D_t* _glFramebufferTexture2D = nullptr; + glDrawBuffers_t* _glDrawBuffers = nullptr; + glBlendFuncSeparate_t* _glBlendFuncSeparate = nullptr; + public: - glCreateShader_t* glCreateShader = nullptr; - glCreateProgram_t* glCreateProgram = nullptr; - glShaderSource_t* glShaderSource = nullptr; - glDeleteShader_t* glDeleteShader = nullptr; - glCompileShader_t* glCompileShader = nullptr; - glLinkProgram_t* glLinkProgram = nullptr; - glDeleteProgram_t* glDeleteProgram = nullptr; - glAttachShader_t* glAttachShader = nullptr; - glBindBuffer_t* glBindBuffer = nullptr; - glBufferData_t* glBufferData = nullptr; - glGenBuffers_t* glGenBuffers = nullptr; - glVertexAttribPointer_t* glVertexAttribPointer = nullptr; - glEnableVertexAttribArray_t* glEnableVertexAttribArray = nullptr; - glUseProgram_t* glUseProgram = nullptr; - glBindVertexArray_t* glBindVertexArray = nullptr; - glGenVertexArrays_t* glGenVertexArrays = nullptr; - glGetShaderInfoLog_t* glGetShaderInfoLog = nullptr; - glGetUniformLocation_t* glGetUniformLocation = nullptr; - glUniform1f_t* glUniform1f = nullptr; - glUniform1i_t* glUniform1i = nullptr; - glUniform2fv_t* glUniform2fv = nullptr; - glUniform4fv_t* glUniform4fv = nullptr; - glUniformMatrix4fv_t* glUniformMatrix4fv = nullptr; - glActiveTexture_t* glActiveTexture = nullptr; - glGenFrameBuffers_t* glGenFrameBuffers = nullptr; - glBindFrameBuffer_t* glBindFrameBuffer = nullptr; - glCheckFrameBufferStatus_t* glCheckFrameBufferStatus = nullptr; - glDeleteFrameBuffers_t* glDeleteFrameBuffers = nullptr; - glFrameBufferTexture2D_t* glFrameBufferTexture2D = nullptr; - glDrawBuffers_t* glDrawBuffers = nullptr; - glBlendFuncSeparate_t* glBlendFuncSeparate = nullptr; + // Proxies allow switchable, clutter-free error checking + + // OpenGL3.3 Proxies + + GLuint glCreateShader(GLenum type); + GLuint glCreateProgram(void); + void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); + void glDeleteShader(GLuint shader); + void glCompileShader(GLuint shader); + void glLinkProgram(GLuint program); + void glDeleteProgram(GLuint program); + void glAttachShader(GLuint program, GLuint shader); + void glBindBuffer(GLenum target, GLuint buffer); + void glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + void glGenBuffers(GLsizei n, GLuint* buffers); + void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); + void glEnableVertexAttribArray(GLuint index); + void glUseProgram(GLuint program); + void glBindVertexArray(GLuint array); + void glGenVertexArrays(GLsizei n, GLuint* arrays); + void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); + GLint glGetUniformLocation(GLuint program, const GLchar* name); + void glUniform1f(GLint location, GLfloat v0); + void glUniform1i(GLint location, GLint v0); + void glUniform2fv(GLint location, GLsizei count, const GLfloat* value); + void glUniform4fv(GLint location, GLsizei count, const GLfloat* value); + void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value); + void glActiveTexture(GLenum texture); + void glGenFramebuffers(GLsizei n, GLuint* ids); + void glBindFramebuffer(GLenum target, GLuint fb); + GLenum glCheckFramebufferStatus(GLenum target); + void glDeleteFramebuffers(GLsizei n, const GLuint* fbs); + void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void glDrawBuffers(GLsizei n, const GLenum* bufs); + void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); // OpenGL1.2 Proxies (just keeps things tidy imo) void glGenTextures(GLsizei n, GLuint* textures); @@ -1958,6 +2022,17 @@ namespace olc void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data); + void glCullFace(GLenum mode); + void glEnable(GLenum cap); + void glDisable(GLenum cap); + void glDrawArrays(GLenum mode, GLint first, GLsizei count); + void glBlendFunc(GLenum sfactor, GLenum dfactor); + void glDepthFunc(GLenum func); + + + + private: + bool CheckError(const std::source_location loc = std::source_location::current()); }; } @@ -1997,6 +2072,7 @@ namespace olc // Destroys a GPU device interface bool DestroyDevice() override; + public: // Texture Resource Stuff // Allocates a new texture resource in VRAM, returns handle uint32_t CreateTexture(const olc::vi2d& vSize, const olc::ImageConfig& cfg = olc::ImageConfig()) override; @@ -2034,6 +2110,10 @@ namespace olc olc::apis::opengl::glRenderContext_t glRenderContext = 0; Shader_GLSL33 shaderDefault; + uint32_t nDefaultVB = 0; + uint32_t nDefaultVA = 0; + uint32_t nDefaultFBO = 0; + olc::Image imgBlank; }; } @@ -2118,8 +2198,9 @@ namespace olc::host { // The user created olc::Window object is the SSoT for what a window // should look like, so get that sort of thing from there - olc::vi2d vWinPos = pWindow->GetPosition(); - olc::vi2d vWinSize = pWindow->GetSize(); + olc::vi2d vWinPos = vWindowPos; + olc::vi2d vWinSize = vWindowSize; + // Define WindowClass WNDCLASS wc = { 0 }; @@ -2159,6 +2240,7 @@ namespace olc::host AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); int width = rWndRect.right - rWndRect.left; int height = rWndRect.bottom - rWndRect.top; + pWindow->SetSize({width, height}); // Create the actual OS window, return a handle HWND hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE3"), olcT(""), dwStyle, @@ -2237,7 +2319,12 @@ namespace olc::host // case WM_MOVE: vWinPos = olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); ptrPGE->olc_UpdateWindowPos(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0; - // case WM_SIZE: vWinSize = olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); ptrPGE->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0; + case WM_SIZE: + { + window->olc_OnWindowSize(olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF)); + return 0; + } + break; // case WM_MOUSEWHEEL: ptrPGE->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); return 0; // case WM_MOUSELEAVE: ptrPGE->olc_UpdateMouseFocus(false); return 0; // case WM_SETFOCUS: ptrPGE->olc_UpdateKeyFocus(true); return 0; @@ -2353,94 +2440,358 @@ namespace olc::apis::opengl { // Load all the OpenGL API entry points bLoaded = true; - bLoaded &= (glCreateShader = OGL_LOAD(glCreateShader)) != nullptr; - bLoaded &= (glCreateProgram = OGL_LOAD(glCreateProgram)) != nullptr; - bLoaded &= (glShaderSource = OGL_LOAD(glShaderSource)) != nullptr; - bLoaded &= (glDeleteShader = OGL_LOAD(glDeleteShader)) != nullptr; - bLoaded &= (glCompileShader = OGL_LOAD(glCompileShader)) != nullptr; - bLoaded &= (glLinkProgram = OGL_LOAD(glLinkProgram)) != nullptr; - bLoaded &= (glDeleteProgram = OGL_LOAD(glDeleteProgram)) != nullptr; - bLoaded &= (glAttachShader = OGL_LOAD(glAttachShader)) != nullptr; - bLoaded &= (glBindBuffer = OGL_LOAD(glBindBuffer)) != nullptr; - bLoaded &= (glBufferData = OGL_LOAD(glBufferData)) != nullptr; - bLoaded &= (glGenBuffers = OGL_LOAD(glGenBuffers)) != nullptr; - bLoaded &= (glVertexAttribPointer = OGL_LOAD(glVertexAttribPointer)) != nullptr; - bLoaded &= (glEnableVertexAttribArray = OGL_LOAD(glEnableVertexAttribArray)) != nullptr; - bLoaded &= (glUseProgram = OGL_LOAD(glUseProgram)) != nullptr; - bLoaded &= (glBindVertexArray = OGL_LOAD(glBindVertexArray)) != nullptr; - bLoaded &= (glGenVertexArrays = OGL_LOAD(glGenVertexArrays)) != nullptr; - bLoaded &= (glGetShaderInfoLog = OGL_LOAD(glGetShaderInfoLog)) != nullptr; - bLoaded &= (glGetUniformLocation = OGL_LOAD(glGetUniformLocation)) != nullptr; - bLoaded &= (glUniform1f = OGL_LOAD(glUniform1f)) != nullptr; - bLoaded &= (glUniform1i = OGL_LOAD(glUniform1i)) != nullptr; - bLoaded &= (glUniform2fv = OGL_LOAD(glUniform2fv)) != nullptr; - bLoaded &= (glUniform4fv = OGL_LOAD(glUniform4fv)) != nullptr; - bLoaded &= (glUniformMatrix4fv = OGL_LOAD(glUniformMatrix4fv)) != nullptr; - bLoaded &= (glActiveTexture = OGL_LOAD(glActiveTexture)) != nullptr; - bLoaded &= (glGenFrameBuffers = OGL_LOAD(glGenFrameBuffers)) != nullptr; - bLoaded &= (glBindFrameBuffer = OGL_LOAD(glBindFrameBuffer)) != nullptr; - bLoaded &= (glCheckFrameBufferStatus = OGL_LOAD(glCheckFrameBufferStatus)) != nullptr; - bLoaded &= (glDeleteFrameBuffers = OGL_LOAD(glDeleteFrameBuffers)) != nullptr; - bLoaded &= (glFrameBufferTexture2D = OGL_LOAD(glFrameBufferTexture2D)) != nullptr; - bLoaded &= (glDrawBuffers = OGL_LOAD(glDrawBuffers)) != nullptr; - bLoaded &= (glBlendFuncSeparate = OGL_LOAD(glBlendFuncSeparate)) != nullptr; - - if (!bLoaded) - return false; // API load has failed - + bLoaded &= (_glCreateShader = OGL_LOAD(glCreateShader)) != nullptr; + bLoaded &= (_glCreateProgram = OGL_LOAD(glCreateProgram)) != nullptr; + bLoaded &= (_glShaderSource = OGL_LOAD(glShaderSource)) != nullptr; + bLoaded &= (_glDeleteShader = OGL_LOAD(glDeleteShader)) != nullptr; + bLoaded &= (_glCompileShader = OGL_LOAD(glCompileShader)) != nullptr; + bLoaded &= (_glLinkProgram = OGL_LOAD(glLinkProgram)) != nullptr; + bLoaded &= (_glDeleteProgram = OGL_LOAD(glDeleteProgram)) != nullptr; + bLoaded &= (_glAttachShader = OGL_LOAD(glAttachShader)) != nullptr; + bLoaded &= (_glBindBuffer = OGL_LOAD(glBindBuffer)) != nullptr; + bLoaded &= (_glBufferData = OGL_LOAD(glBufferData)) != nullptr; + bLoaded &= (_glGenBuffers = OGL_LOAD(glGenBuffers)) != nullptr; + bLoaded &= (_glVertexAttribPointer = OGL_LOAD(glVertexAttribPointer)) != nullptr; + bLoaded &= (_glEnableVertexAttribArray = OGL_LOAD(glEnableVertexAttribArray)) != nullptr; + bLoaded &= (_glUseProgram = OGL_LOAD(glUseProgram)) != nullptr; + bLoaded &= (_glBindVertexArray = OGL_LOAD(glBindVertexArray)) != nullptr; + bLoaded &= (_glGenVertexArrays = OGL_LOAD(glGenVertexArrays)) != nullptr; + bLoaded &= (_glGetShaderInfoLog = OGL_LOAD(glGetShaderInfoLog)) != nullptr; + bLoaded &= (_glGetUniformLocation = OGL_LOAD(glGetUniformLocation)) != nullptr; + bLoaded &= (_glUniform1f = OGL_LOAD(glUniform1f)) != nullptr; + bLoaded &= (_glUniform1i = OGL_LOAD(glUniform1i)) != nullptr; + bLoaded &= (_glUniform2fv = OGL_LOAD(glUniform2fv)) != nullptr; + bLoaded &= (_glUniform4fv = OGL_LOAD(glUniform4fv)) != nullptr; + bLoaded &= (_glUniformMatrix4fv = OGL_LOAD(glUniformMatrix4fv)) != nullptr; + bLoaded &= (_glActiveTexture = OGL_LOAD(glActiveTexture)) != nullptr; + bLoaded &= (_glGenFramebuffers = OGL_LOAD(glGenFramebuffers)) != nullptr; + bLoaded &= (_glBindFramebuffer = OGL_LOAD(glBindFramebuffer)) != nullptr; + bLoaded &= (_glCheckFramebufferStatus = OGL_LOAD(glCheckFramebufferStatus)) != nullptr; + bLoaded &= (_glDeleteFramebuffers = OGL_LOAD(glDeleteFramebuffers)) != nullptr; + bLoaded &= (_glFramebufferTexture2D = OGL_LOAD(glFramebufferTexture2D)) != nullptr; + bLoaded &= (_glDrawBuffers = OGL_LOAD(glDrawBuffers)) != nullptr; + bLoaded &= (_glBlendFuncSeparate = OGL_LOAD(glBlendFuncSeparate)) != nullptr; + + return bLoaded; + } + bool gl::CheckError(const std::source_location loc) + { +#if OLC_GPU_ERRORCHECK == 1 + GLenum err; + bool bWasError = false; + std::stringstream sLocation; + sLocation + << loc.file_name() << '(' + << loc.line() << ':' + << loc.column() << ") `" + << loc.function_name() << "`: "; + while ((err = ::glGetError()) != GL_NO_ERROR) + { + switch (err) + { + case GL_INVALID_ENUM: + sLocation << "OGL33 Error: GL_INVALID_ENUM\n"; break; + case GL_INVALID_VALUE: + sLocation << "OGL33 Error: GL_INVALID_VALUE\n"; break; + case GL_INVALID_OPERATION: + sLocation << "OGL33 Error: GL_INVALID_OPERATION\n"; break; + case 0x0506: //GL_INVALID_FRAMEBUFFER_OPERATION: + sLocation << "OGL33 Error: GL_INVALID_FRAMEBUFFER_OPERATION\n"; break; + case GL_OUT_OF_MEMORY: + sLocation << "OGL33 Error: GL_OUT_OF_MEMORY\n"; break; + case GL_STACK_UNDERFLOW: + sLocation << "OGL33 Error: GL_STACK_UNDERFLOW\n"; break; + case GL_STACK_OVERFLOW: + sLocation << "OGL33 Error: GL_STACK_OVERFLOW\n"; break; + } + bWasError = true; - return bLoaded; + std::cout << sLocation.str() << "\n"; + sLocation.clear(); + } + return bWasError; +#else + return false; +#endif } void gl::glGenTextures(GLsizei n, GLuint* textures) { ::glGenTextures(n, textures); + CheckError(); } void gl::glBindTexture(GLenum target, GLuint texture) { ::glBindTexture(target, texture); + CheckError(); } void gl::glTexParameteri(GLenum target, GLenum pname, GLint param) { ::glTexParameteri(target, pname, param); + CheckError(); } void gl::glTexEnvf(GLenum target, GLenum pname, GLfloat param) { ::glTexEnvf(target, pname, param); + CheckError(); } void gl::glDeleteTextures(GLsizei n, const GLuint* textures) { ::glDeleteTextures(n, textures); + CheckError(); } void gl::glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + CheckError(); } void gl::glClear(GLbitfield mask) { ::glClear(mask); + CheckError(); } void gl::glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { ::glViewport(x, y, width, height); + CheckError(); } void gl::glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { ::glClearColor(red, green, blue, alpha); + CheckError(); } void gl::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* data) { ::glReadPixels(x, y, width, height, format, type, data); + CheckError(); + } + + void gl::glCullFace(GLenum mode) + { + ::glCullFace(mode); + CheckError(); + } + + void gl::glEnable(GLenum cap) + { + ::glEnable(cap); + CheckError(); + } + + void gl::glDisable(GLenum cap) + { + ::glDisable(cap); + CheckError(); + } + + void gl::glDrawArrays(GLenum mode, GLint first, GLsizei count) + { + ::glDrawArrays(mode, first, count); + CheckError(); + } + + void gl::glBlendFunc(GLenum sfactor, GLenum dfactor) + { + ::glBlendFunc(sfactor, dfactor); + CheckError(); + } + + void gl::glDepthFunc(GLenum func) + { + ::glDepthFunc(func); + CheckError(); + } + + GLuint gl::glCreateShader(GLenum type) + { + return _glCreateShader(type); + } + + GLuint gl::glCreateProgram(void) + { + return _glCreateProgram(); + } + + void gl::glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) + { + _glShaderSource(shader, count, string, length); + CheckError(); + } + + void gl::glDeleteShader(GLuint shader) + { + _glDeleteShader(shader); + CheckError(); + } + + void gl::glCompileShader(GLuint shader) + { + _glCompileShader(shader); + CheckError(); + } + + void gl::glLinkProgram(GLuint program) + { + _glLinkProgram(program); + CheckError(); + } + + void gl::glDeleteProgram(GLuint program) + { + _glDeleteProgram(program); + CheckError(); + } + + void gl::glAttachShader(GLuint program, GLuint shader) + { + _glAttachShader(program, shader); + CheckError(); + } + + void gl::glBindBuffer(GLenum target, GLuint buffer) + { + _glBindBuffer(target, buffer); + CheckError(); + } + + void gl::glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) + { + _glBufferData(target, size, data, usage); + CheckError(); + } + + void gl::glGenBuffers(GLsizei n, GLuint* buffers) + { + _glGenBuffers(n, buffers); + CheckError(); + } + + void gl::glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) + { + _glVertexAttribPointer(index, size, type, normalized, stride, pointer); + CheckError(); + } + + void gl::glEnableVertexAttribArray(GLuint index) + { + _glEnableVertexAttribArray(index); + CheckError(); + } + + void gl::glUseProgram(GLuint program) + { + _glUseProgram(program); + CheckError(); + } + + void gl::glBindVertexArray(GLuint array) + { + _glBindVertexArray(array); + CheckError(); + } + + void gl::glGenVertexArrays(GLsizei n, GLuint* arrays) + { + _glGenVertexArrays(n, arrays); + CheckError(); + } + + void gl::glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) + { + _glGetShaderInfoLog(shader, bufSize, length, infoLog); + CheckError(); + } + + GLint gl::glGetUniformLocation(GLuint program, const GLchar* name) + { + return _glGetUniformLocation(program, name); + } + + void gl::glUniform1f(GLint location, GLfloat v0) + { + _glUniform1f(location, v0); + CheckError(); + } + + void gl::glUniform1i(GLint location, GLint v0) + { + _glUniform1i(location, v0); + CheckError(); + } + + void gl::glUniform2fv(GLint location, GLsizei count, const GLfloat* value) + { + _glUniform2fv(location, count, value); + CheckError(); + } + + void gl::glUniform4fv(GLint location, GLsizei count, const GLfloat* value) + { + _glUniform4fv(location, count, value); + CheckError(); + } + + void gl::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value) + { + _glUniformMatrix4fv(location, count, trasnpose, value); + CheckError(); + } + + void gl::glActiveTexture(GLenum texture) + { + _glActiveTexture(texture); + CheckError(); + } + + void gl::glGenFramebuffers(GLsizei n, GLuint* ids) + { + _glGenFramebuffers(n, ids); + CheckError(); + } + + void gl::glBindFramebuffer(GLenum target, GLuint fb) + { + _glBindFramebuffer(target, fb); + CheckError(); + } + + GLenum gl::glCheckFramebufferStatus(GLenum target) + { + return _glCheckFramebufferStatus(target); + } + + void gl::glDeleteFramebuffers(GLsizei n, const GLuint* fbs) + { + _glDeleteFramebuffers(n, fbs); + CheckError(); + } + + void gl::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + { + _glFramebufferTexture2D(target, attachment, textarget, texture, level); + CheckError(); + } + + void gl::glDrawBuffers(GLsizei n, const GLenum* bufs) + { + _glDrawBuffers(n, bufs); + CheckError(); + } + + void gl::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + { + _glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + CheckError(); } } namespace olc::gpu @@ -2552,11 +2903,18 @@ namespace olc::gpu // Can't load OpenGL API until context is loaded auto& gl = olc::apis::opengl::gl::Get(); + if (!gl.HasLoaded()) + { + std::cout << "Error: Could not Load OpenGL!\n"; + lastError = RendererError::None; + return false; + } + - + // Create "Default" Shader shaderDefault.SetPixelShaderSource( "#version 330 core\n" - "out vec4 pixel;\n" + "layout(location = 0) out vec4 pixel;\n" "in vec2 oTex;\n" "in vec4 oCol;\n" "uniform sampler2D sprTex;\n" @@ -2566,8 +2924,8 @@ namespace olc::gpu shaderDefault.SetVertexShaderSource( "#version 330 core\n" "layout(location = 0) in vec4 aPos;\n" - "layout(location = 1) in vec2 aTex;\n" - "layout(location = 2) in vec4 aCol;\n" + "layout(location = 1) in vec4 aCol;\n" + "layout(location = 2) in vec2 aTex;\n" "uniform mat4 mvp;\n" "uniform int is3d;\n" "uniform vec4 tint;\n" @@ -2581,6 +2939,70 @@ namespace olc::gpu shaderDefault.CreateUniform("is3d"); shaderDefault.CreateUniform("tint"); + // Create "Default" Vertex Buffer / Vertex Attributes. This buffer is reused + // for all drawing operations. It's possible future versions may allow the + // creation of additional named buffers for repeated drawing operations with + // minimal overhead. + gl.glGenBuffers(1, &nDefaultVB); + gl.glGenVertexArrays(1, &nDefaultVA); + gl.glBindVertexArray(nDefaultVA); + gl.glBindBuffer(0x8892, nDefaultVB); + + // A big one is allocated to reduce shuffles in GPU memory + GPUTask::Vertex verts[OLC_GPU_MAX_VERTICES]; + gl.glBufferData(0x8892, sizeof(GPUTask::Vertex) * OLC_GPU_MAX_VERTICES, verts, 0x88E0); + + // Float Index 0 = x, 1 = y, 2 = z, 3 = w + gl.glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(0 * sizeof(float))); + gl.glEnableVertexAttribArray(0); + // Float Index 4 = (RGBA 8-bit x4) + gl.glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GPUTask::Vertex), (void*)(4 * sizeof(float))); + gl.glEnableVertexAttribArray(1); + // Float Index 5 = u0, 6 = v0 + gl.glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(5 * sizeof(float))); + gl.glEnableVertexAttribArray(2); + // Float Index 7 = u1, 8 = v1 + gl.glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(7 * sizeof(float))); + gl.glEnableVertexAttribArray(3); + // Float Index 9 = u2, 10 = v2 + gl.glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(9 * sizeof(float))); + gl.glEnableVertexAttribArray(4); + // Float Index 11 = u3, 12 = v4 + gl.glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(11 * sizeof(float))); + gl.glEnableVertexAttribArray(5); + + // Buffers are configured, unbind for now + gl.glBindBuffer(0x8892, 0); + gl.glBindVertexArray(0); + + + + + + // Create a null-texture so sampler doesnt fail. We don't have some of the core's helper + // functions here, so we construct it manually + imgBlank.Create({ 1,1 }); + imgBlank.SetGPUID(CreateTexture(imgBlank.Size())); + imgBlank.BindCPU(); + imgBlank.Data({ 0,0 }) = olc::Colour::WHITE; + imgBlank.BindGPU(); + WriteTexture(imgBlank.GetGPUID(), imgBlank); + + // Create a Frame Buffer Object for off-screen rendering things + gl.glGenFramebuffers(1, (GLuint*)&nDefaultFBO); + gl.glBindFramebuffer(36160U, nDefaultFBO); // GL_FRAMEBUFFER + // Attach 4 colour buffers + std::array attachments = { {36064U, 36065U, 36066U, 36067U} }; + gl.glDrawBuffers(4, attachments.data()); + // Unlink them from any existing image textures + //gl.glFramebufferTexture2D(36160U, attachments[0], GL_TEXTURE_2D, 0, 0); + //gl.glFramebufferTexture2D(36160U, attachments[1], GL_TEXTURE_2D, 0, 0); + //gl.glFramebufferTexture2D(36160U, attachments[2], GL_TEXTURE_2D, 0, 0); + //gl.glFramebufferTexture2D(36160U, attachments[3], GL_TEXTURE_2D, 0, 0); + // Unbind the FBO + gl.glBindFramebuffer(36160U, 0); + + lastError = RendererError::None; return true; @@ -2633,6 +3055,7 @@ namespace olc::gpu #if OLC_HOST != OLC_HOST_EMSCRIPTEN gl.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #endif + return id; } @@ -2662,13 +3085,31 @@ namespace olc::gpu bool Renderer_OGL33::AssignTextureSource(const uint32_t slot, const uint32_t texid) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + + gl.glActiveTexture(0x84C0 + slot); // GL_TEXTURE0 + gl.glBindTexture(GL_TEXTURE_2D, texid); + return true; } bool Renderer_OGL33::AssignTextureTarget(const uint32_t slot, const uint32_t texid) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + + if (texid == 0) + { + gl.glBindFramebuffer(36160U, 0); + return true; + } + + // Bind FBO + gl.glBindFramebuffer(36160U, nDefaultFBO); + // Allocate target buffers + std::array attachments = + { { 36064U, 36065U, 36066U, 36067U, 36068U, 36069U, 36070U, 36071U } }; + gl.glDrawBuffers(1, attachments.data()); + // Bind buffers to textures + gl.glFramebufferTexture2D(36160U, 36064U + slot, GL_TEXTURE_2D, texid, 0); + return true; } bool Renderer_OGL33::ApplyShader(const Shader& shader) @@ -2689,10 +3130,81 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); + switch (task.task) + { + case GPUTask::Task::DrawPolygon: + { + if (task.pImage == nullptr) + AssignTextureSource(0, imgBlank.GetGPUID()); + else + AssignTextureSource(0, task.pImage->GetGPUID()); + + // Bind generic vertex buffer + gl.glBindVertexArray(nDefaultVA); + gl.glBindBuffer(0x8892, nDefaultVB); + + // Copy data from CPU to GPU + gl.glBufferData(0x8892, sizeof(GPUTask::Vertex) * task.vertexBuffer.size(), task.vertexBuffer.data(), 0x88E0); + + // Shader: Configure Rendering Mode + gl.glUniform1i(shaderDefault.GetUniform("is3d"), 0); + + // Shader: Apply MVP Matrix + gl.glUniformMatrix4fv(shaderDefault.GetUniform("mvp"), 1, false, task.mvpMatrix.data()); + + // Shader: Apply Global Tint + float f[4] = { + float(task.tint.r) / 255.0f, + float(task.tint.g) / 255.0f, + float(task.tint.b) / 255.0f, + float(task.tint.a) / 255.0f + }; + gl.glUniform4fv(shaderDefault.GetUniform("tint"), 1, f); + + // Apply Culling modes + if (task.cullmode == GPUTask::CullMode::None) + { + gl.glCullFace(GL_FRONT); + gl.glDisable(GL_CULL_FACE); + } + else if (task.cullmode == GPUTask::CullMode::ClockWise) + { + gl.glCullFace(GL_FRONT); + gl.glEnable(GL_CULL_FACE); + } + else if (task.cullmode == GPUTask::CullMode::CounterClockWise) + { + gl.glCullFace(GL_BACK); + gl.glEnable(GL_CULL_FACE); + } + + // Apply Depth Testing (if required) + if (task.bDepth) + gl.glEnable(GL_DEPTH_TEST); + + // Draw the thing! + if (task.bWireframe) + { + gl.glDrawArrays(GL_LINE_LOOP, 0, (GLsizei)task.vertexBuffer.size()); + } + else + { + if (task.structure == GPUTask::Structure::Fan) + gl.glDrawArrays(GL_TRIANGLE_FAN, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::Strip) + gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::List) + gl.glDrawArrays(GL_TRIANGLES, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::Line) + gl.glDrawArrays(GL_LINES, 0, (GLsizei)task.vertexBuffer.size()); + } + + if (task.bDepth) + gl.glDisable(GL_DEPTH_TEST); - - - + } + break; + } return true; } @@ -2709,12 +3221,18 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); gl.glViewport(int(pos.x), int(pos.y), int(size.x), int(size.y)); - return false; + return true; } bool Renderer_OGL33::DisplayPrepare() { auto& gl = olc::apis::opengl::gl::Get(); + + //gl.glUseProgram(shaderDefault.GetShaderID()); + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl.glDepthFunc(GL_LESS); + //gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); + return false; } @@ -2806,7 +3324,7 @@ void Draw2D::PrepareTargetForHW() void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { PrepareTargetForSW(); - pTarget->Data(transform.forward(pos)) = col; + pTarget->Data(transform.forward(((pos + 1.0f) * 0.5f) * olc::vf2d(pTarget->Size()))) = col; } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) @@ -2817,9 +3335,10 @@ GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::ve GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) { GPUTask task; + task.structure = structure; task.bWireframe = true; for (const auto& v : vPoints) - task.vertexBuffer.push_back({ v.x, v.y, 0.0f, 0.0f, 0.0f, 0.0f, colour }); + task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, colour, 0, 0, 0,0, 0, 0, 0, 0 }); task.tint = tint; return task; } @@ -2831,12 +3350,22 @@ GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::ve GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) { - return GPUTask(); + GPUTask task; + task.structure = structure; + for (const auto& v : vPoints) + task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, colour, 0, 0, 0,0, 0, 0, 0, 0 }); + task.tint = tint; + return task; } -GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) +GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) { - return GPUTask(); + GPUTask task; + for (size_t i = 0; i({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + col, + olc::Colour::WHITE + )); +} + +GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskTexturedPolygon( + GPUTask::Structure::Fan, + transform.forward({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, + { {0,0}, {1,0}, {1,1}, {0,1} }, + &image + )); +} + #define PGE_DRAW2D_IMPLEMENTED 1 #endif @@ -2902,7 +3456,7 @@ namespace olc // Link this olc::Window to a host resource if (host) - host->AddWindowFrame(this, { 30,30 }, { 250, 240 }, false); + host->AddWindowFrame(this, { 30,30 }, config.vPixelSize * config.vScreenSize, false); coreActive = true; coreThread = std::thread(&PixelGameEngine::EngineThread, this); @@ -3013,7 +3567,8 @@ namespace olc } - CreateImage(imgPrimary, GetSize()); + CreateImage(imgPrimary, config.vScreenSize); + gpu->WriteTexture(imgPrimary.GetGPUID(), imgPrimary); if (!OnUserCreate()) { @@ -3070,7 +3625,7 @@ namespace olc // Wait for vertical sync if required. // Note: Child windows will never vsync as waiting for each buffer swap with vsync - // divides up teh frame rate budget across the windows. + // divides up the frame rate budget across the windows. if (gpu->GetConfig().VerticalSync) { host->SyncWithDesktopComposite(); @@ -3238,7 +3793,7 @@ namespace olc bool Window::olc_OnWindowSize(const olc::vi2d& vWindowSize) { - return false; + return SetSize(vWindowSize); } bool Window::olc_ShouldRemove() const @@ -3254,8 +3809,15 @@ namespace olc draw.SetGPU(gpu); draw.SetTarget(imgPrimary); - gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::TANGERINE, false, false); + + gpu->DisplayPrepare(); + + + gpu->AssignTextureTarget(0, imgPrimary.GetGPUID()); + gpu->SetViewport({ 0,0 }, imgPrimary.Size()); + gpu->ClearViewport(olc::Colour::BLACK, true, true); + + gpu->ApplyDefaultShader(); // User Update if (!OnUserUpdate(fElapsedTime)) @@ -3268,9 +3830,17 @@ namespace olc } } + // Finialise any outstanding tasks draw.ProcessGPUTasks(); + // Take the window's completed "screen" and draw it as a textured quad to the backbuffer + gpu->AssignTextureTarget(0, 0); + gpu->SetViewport({ 0,0 }, GetSize()); + gpu->ClearViewport(olc::Colour::TANGERINE, true, true); + draw.Image(imgPrimary, { -1.0,-1.0 }, { 2.0f,2.0f }); + draw.ProcessGPUTasks(); + // Update Window's primary surface gpu->DisplayDraw(); diff --git a/dev/msvc/olcPGE3_BuildSH/test_sh.cpp b/dev/msvc/olcPGE3_BuildSH/test_sh.cpp index f8c3480b..88744338 100644 --- a/dev/msvc/olcPGE3_BuildSH/test_sh.cpp +++ b/dev/msvc/olcPGE3_BuildSH/test_sh.cpp @@ -17,6 +17,18 @@ class Example : public olc::PixelGameEngine bool OnUserUpdate(float fElapsedTime) override { + draw.Line({ 0,0 }, { 1, 1 }, olc::Colour::RED); + draw.Line({ 0,0 }, { 1, -1 }, olc::Colour::GREEN); + draw.Line({ 0,0 }, { -1, -1 }, olc::Colour::CYAN); + draw.Line({ 0,0 }, { -1, 1 }, olc::Colour::WHITE); + + draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); + + draw.FillRect({ 0.25f, 0.25f }, { 0.3f, 0.6f }, olc::Colour::TANGERINE); + + draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); + draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); + draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); return true; } }; diff --git a/dev/src/api_opengl.cpp b/dev/src/api_opengl.cpp index ee1e5116..37537e7e 100644 --- a/dev/src/api_opengl.cpp +++ b/dev/src/api_opengl.cpp @@ -41,19 +41,14 @@ namespace olc::apis::opengl bLoaded &= (_glUniform4fv = OGL_LOAD(glUniform4fv)) != nullptr; bLoaded &= (_glUniformMatrix4fv = OGL_LOAD(glUniformMatrix4fv)) != nullptr; bLoaded &= (_glActiveTexture = OGL_LOAD(glActiveTexture)) != nullptr; - bLoaded &= (_glGenFrameBuffers = OGL_LOAD(glGenFrameBuffers)) != nullptr; - bLoaded &= (_glBindFrameBuffer = OGL_LOAD(glBindFrameBuffer)) != nullptr; - bLoaded &= (_glCheckFrameBufferStatus = OGL_LOAD(glCheckFrameBufferStatus)) != nullptr; - bLoaded &= (_glDeleteFrameBuffers = OGL_LOAD(glDeleteFrameBuffers)) != nullptr; - bLoaded &= (_glFrameBufferTexture2D = OGL_LOAD(glFrameBufferTexture2D)) != nullptr; + bLoaded &= (_glGenFramebuffers = OGL_LOAD(glGenFramebuffers)) != nullptr; + bLoaded &= (_glBindFramebuffer = OGL_LOAD(glBindFramebuffer)) != nullptr; + bLoaded &= (_glCheckFramebufferStatus = OGL_LOAD(glCheckFramebufferStatus)) != nullptr; + bLoaded &= (_glDeleteFramebuffers = OGL_LOAD(glDeleteFramebuffers)) != nullptr; + bLoaded &= (_glFramebufferTexture2D = OGL_LOAD(glFramebufferTexture2D)) != nullptr; bLoaded &= (_glDrawBuffers = OGL_LOAD(glDrawBuffers)) != nullptr; bLoaded &= (_glBlendFuncSeparate = OGL_LOAD(glBlendFuncSeparate)) != nullptr; - - if (!bLoaded) - return false; // API load has failed - - - + return bLoaded; } @@ -335,32 +330,32 @@ namespace olc::apis::opengl CheckError(); } - void gl::glGenFrameBuffers(GLsizei n, GLuint* ids) + void gl::glGenFramebuffers(GLsizei n, GLuint* ids) { - _glGenFrameBuffers(n, ids); + _glGenFramebuffers(n, ids); CheckError(); } - void gl::glBindFrameBuffer(GLenum target, GLuint fb) + void gl::glBindFramebuffer(GLenum target, GLuint fb) { - _glBindFrameBuffer(target, fb); + _glBindFramebuffer(target, fb); CheckError(); } - GLenum gl::glCheckFrameBufferStatus(GLenum target) + GLenum gl::glCheckFramebufferStatus(GLenum target) { - return _glCheckFrameBufferStatus(target); + return _glCheckFramebufferStatus(target); } - void gl::glDeleteFrameBuffers(GLsizei n, const GLuint* fbs) + void gl::glDeleteFramebuffers(GLsizei n, const GLuint* fbs) { - _glDeleteFrameBuffers(n, fbs); + _glDeleteFramebuffers(n, fbs); CheckError(); } - void gl::glFrameBufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + void gl::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - _glFrameBufferTexture2D(target, attachment, textarget, texture, level); + _glFramebufferTexture2D(target, attachment, textarget, texture, level); CheckError(); } diff --git a/dev/src/api_opengl.h b/dev/src/api_opengl.h index b1b65a2f..bfc94d9f 100644 --- a/dev/src/api_opengl.h +++ b/dev/src/api_opengl.h @@ -97,11 +97,11 @@ namespace olc typedef void CALLSTYLE glUniform4fv_t(GLint location, GLsizei count, const GLfloat* value); typedef void CALLSTYLE glUniformMatrix4fv_t(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value); typedef void CALLSTYLE glActiveTexture_t(GLenum texture); - typedef void CALLSTYLE glGenFrameBuffers_t(GLsizei n, GLuint* ids); - typedef void CALLSTYLE glBindFrameBuffer_t(GLenum target, GLuint fb); - typedef GLenum CALLSTYLE glCheckFrameBufferStatus_t(GLenum target); - typedef void CALLSTYLE glDeleteFrameBuffers_t(GLsizei n, const GLuint* fbs); - typedef void CALLSTYLE glFrameBufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + typedef void CALLSTYLE glGenFramebuffers_t(GLsizei n, GLuint* ids); + typedef void CALLSTYLE glBindFramebuffer_t(GLenum target, GLuint fb); + typedef GLenum CALLSTYLE glCheckFramebufferStatus_t(GLenum target); + typedef void CALLSTYLE glDeleteFramebuffers_t(GLsizei n, const GLuint* fbs); + typedef void CALLSTYLE glFramebufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void CALLSTYLE glDrawBuffers_t(GLsizei n, const GLenum* bufs); typedef void CALLSTYLE glBlendFuncSeparate_t(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); @@ -116,6 +116,7 @@ namespace olc { public: static gl& Get(); + inline bool HasLoaded() const { return bLoaded; } private: gl() = default; @@ -149,11 +150,11 @@ namespace olc glUniform4fv_t* _glUniform4fv = nullptr; glUniformMatrix4fv_t* _glUniformMatrix4fv = nullptr; glActiveTexture_t* _glActiveTexture = nullptr; - glGenFrameBuffers_t* _glGenFrameBuffers = nullptr; - glBindFrameBuffer_t* _glBindFrameBuffer = nullptr; - glCheckFrameBufferStatus_t* _glCheckFrameBufferStatus = nullptr; - glDeleteFrameBuffers_t* _glDeleteFrameBuffers = nullptr; - glFrameBufferTexture2D_t* _glFrameBufferTexture2D = nullptr; + glGenFramebuffers_t* _glGenFramebuffers = nullptr; + glBindFramebuffer_t* _glBindFramebuffer = nullptr; + glCheckFramebufferStatus_t* _glCheckFramebufferStatus = nullptr; + glDeleteFramebuffers_t* _glDeleteFramebuffers = nullptr; + glFramebufferTexture2D_t* _glFramebufferTexture2D = nullptr; glDrawBuffers_t* _glDrawBuffers = nullptr; glBlendFuncSeparate_t* _glBlendFuncSeparate = nullptr; @@ -186,11 +187,11 @@ namespace olc void glUniform4fv(GLint location, GLsizei count, const GLfloat* value); void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trasnpose, const GLfloat* value); void glActiveTexture(GLenum texture); - void glGenFrameBuffers(GLsizei n, GLuint* ids); - void glBindFrameBuffer(GLenum target, GLuint fb); - GLenum glCheckFrameBufferStatus(GLenum target); - void glDeleteFrameBuffers(GLsizei n, const GLuint* fbs); - void glFrameBufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void glGenFramebuffers(GLsizei n, GLuint* ids); + void glBindFramebuffer(GLenum target, GLuint fb); + GLenum glCheckFramebufferStatus(GLenum target); + void glDeleteFramebuffers(GLsizei n, const GLuint* fbs); + void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); void glDrawBuffers(GLsizei n, const GLenum* bufs); void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); diff --git a/dev/src/core.cpp b/dev/src/core.cpp index 8e515a51..93dbdd22 100644 --- a/dev/src/core.cpp +++ b/dev/src/core.cpp @@ -149,7 +149,8 @@ namespace olc } - CreateImage(imgPrimary, { 200, 200 }); + CreateImage(imgPrimary, config.vScreenSize); + gpu->WriteTexture(imgPrimary.GetGPUID(), imgPrimary); if (!OnUserCreate()) { diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index eae3202c..23843b53 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -72,7 +72,7 @@ void Draw2D::PrepareTargetForHW() void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { PrepareTargetForSW(); - pTarget->Data(transform.forward(pos)) = col; + pTarget->Data(transform.forward(((pos + 1.0f) * 0.5f) * olc::vf2d(pTarget->Size()))) = col; } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) @@ -83,9 +83,10 @@ GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::ve GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) { GPUTask task; + task.structure = structure; task.bWireframe = true; for (const auto& v : vPoints) - task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, 0.0f, 0.0f, colour }); + task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, colour, 0, 0, 0,0, 0, 0, 0, 0 }); task.tint = tint; return task; } @@ -97,12 +98,22 @@ GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::ve GPUTask olc::Draw2D::TaskFillPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) { - return GPUTask(); + GPUTask task; + task.structure = structure; + for (const auto& v : vPoints) + task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, colour, 0, 0, 0,0, 0, 0, 0, 0 }); + task.tint = tint; + return task; } -GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) +GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) { - return GPUTask(); + GPUTask task; + for (size_t i = 0; i({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + col, + olc::Colour::WHITE + )); +} + +GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskTexturedPolygon( + GPUTask::Structure::Fan, + transform.forward({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, + { {0,0}, {1,0}, {1,1}, {0,1} }, + &image + )); +} + //! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index bf9bacb4..3b643b7a 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -93,6 +93,7 @@ namespace olc GPUTask TaskTexturedPolygon( GPUTask::Structure structure, + const std::vector& vPoints, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, @@ -105,6 +106,12 @@ namespace olc GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); // Draws a single pixel wide line with a gradient GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + + // Draws a filled, single colour rectangle + GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + + // Draws a filled, single colour rectangle + GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); }; } #define PGE_DRAW2D_DECLARED diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index b9e92479..1c957d53 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -110,11 +110,18 @@ namespace olc::gpu // Can't load OpenGL API until context is loaded auto& gl = olc::apis::opengl::gl::Get(); + if (!gl.HasLoaded()) + { + std::cout << "Error: Could not Load OpenGL!\n"; + lastError = RendererError::None; + return false; + } + // Create "Default" Shader shaderDefault.SetPixelShaderSource( "#version 330 core\n" - "out vec4 pixel;\n" + "layout(location = 0) out vec4 pixel;\n" "in vec2 oTex;\n" "in vec4 oCol;\n" "uniform sampler2D sprTex;\n" @@ -124,8 +131,8 @@ namespace olc::gpu shaderDefault.SetVertexShaderSource( "#version 330 core\n" "layout(location = 0) in vec4 aPos;\n" - "layout(location = 1) in vec2 aTex;\n" - "layout(location = 2) in vec4 aCol;\n" + "layout(location = 1) in vec4 aCol;\n" + "layout(location = 2) in vec2 aTex;\n" "uniform mat4 mvp;\n" "uniform int is3d;\n" "uniform vec4 tint;\n" @@ -154,19 +161,31 @@ namespace olc::gpu // Float Index 0 = x, 1 = y, 2 = z, 3 = w gl.glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(0 * sizeof(float))); - gl.glEnableVertexAttribArray(0); - // Float Index 4 = u, 5 = v - gl.glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(4 * sizeof(float))); + gl.glEnableVertexAttribArray(0); + // Float Index 4 = (RGBA 8-bit x4) + gl.glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GPUTask::Vertex), (void*)(4 * sizeof(float))); gl.glEnableVertexAttribArray(1); - // Float Index 6 = (RGBA 8-bit x4) - gl.glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GPUTask::Vertex), (void*)(6 * sizeof(float))); + // Float Index 5 = u0, 6 = v0 + gl.glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(5 * sizeof(float))); gl.glEnableVertexAttribArray(2); + // Float Index 7 = u1, 8 = v1 + gl.glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(7 * sizeof(float))); + gl.glEnableVertexAttribArray(3); + // Float Index 9 = u2, 10 = v2 + gl.glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(9 * sizeof(float))); + gl.glEnableVertexAttribArray(4); + // Float Index 11 = u3, 12 = v4 + gl.glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(GPUTask::Vertex), (void*)(11 * sizeof(float))); + gl.glEnableVertexAttribArray(5); // Buffers are configured, unbind for now gl.glBindBuffer(0x8892, 0); gl.glBindVertexArray(0); + + + // Create a null-texture so sampler doesnt fail. We don't have some of the core's helper // functions here, so we construct it manually imgBlank.Create({ 1,1 }); @@ -176,6 +195,20 @@ namespace olc::gpu imgBlank.BindGPU(); WriteTexture(imgBlank.GetGPUID(), imgBlank); + // Create a Frame Buffer Object for off-screen rendering things + gl.glGenFramebuffers(1, (GLuint*)&nDefaultFBO); + gl.glBindFramebuffer(36160U, nDefaultFBO); // GL_FRAMEBUFFER + // Attach 4 colour buffers + std::array attachments = { {36064U, 36065U, 36066U, 36067U} }; + gl.glDrawBuffers(4, attachments.data()); + // Unlink them from any existing image textures + //gl.glFramebufferTexture2D(36160U, attachments[0], GL_TEXTURE_2D, 0, 0); + //gl.glFramebufferTexture2D(36160U, attachments[1], GL_TEXTURE_2D, 0, 0); + //gl.glFramebufferTexture2D(36160U, attachments[2], GL_TEXTURE_2D, 0, 0); + //gl.glFramebufferTexture2D(36160U, attachments[3], GL_TEXTURE_2D, 0, 0); + // Unbind the FBO + gl.glBindFramebuffer(36160U, 0); + lastError = RendererError::None; @@ -229,6 +262,7 @@ namespace olc::gpu #if OLC_HOST != OLC_HOST_EMSCRIPTEN gl.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #endif + return id; } @@ -258,13 +292,31 @@ namespace olc::gpu bool Renderer_OGL33::AssignTextureSource(const uint32_t slot, const uint32_t texid) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + + gl.glActiveTexture(0x84C0 + slot); // GL_TEXTURE0 + gl.glBindTexture(GL_TEXTURE_2D, texid); + return true; } bool Renderer_OGL33::AssignTextureTarget(const uint32_t slot, const uint32_t texid) { auto& gl = olc::apis::opengl::gl::Get(); - return false; + + if (texid == 0) + { + gl.glBindFramebuffer(36160U, 0); + return true; + } + + // Bind FBO + gl.glBindFramebuffer(36160U, nDefaultFBO); + // Allocate target buffers + std::array attachments = + { { 36064U, 36065U, 36066U, 36067U, 36068U, 36069U, 36070U, 36071U } }; + gl.glDrawBuffers(1, attachments.data()); + // Bind buffers to textures + gl.glFramebufferTexture2D(36160U, 36064U + slot, GL_TEXTURE_2D, texid, 0); + return true; } bool Renderer_OGL33::ApplyShader(const Shader& shader) @@ -289,6 +341,11 @@ namespace olc::gpu { case GPUTask::Task::DrawPolygon: { + if (task.pImage == nullptr) + AssignTextureSource(0, imgBlank.GetGPUID()); + else + AssignTextureSource(0, task.pImage->GetGPUID()); + // Bind generic vertex buffer gl.glBindVertexArray(nDefaultVA); gl.glBindBuffer(0x8892, nDefaultVB); @@ -381,7 +438,7 @@ namespace olc::gpu //gl.glUseProgram(shaderDefault.GetShaderID()); gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl.glDepthFunc(GL_LESS); - gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); + //gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); return false; } diff --git a/dev/src/gpu_opengl33.h b/dev/src/gpu_opengl33.h index 8ed63db6..53f16f51 100644 --- a/dev/src/gpu_opengl33.h +++ b/dev/src/gpu_opengl33.h @@ -64,6 +64,7 @@ namespace olc Shader_GLSL33 shaderDefault; uint32_t nDefaultVB = 0; uint32_t nDefaultVA = 0; + uint32_t nDefaultFBO = 0; olc::Image imgBlank; }; diff --git a/dev/src/gputask.h b/dev/src/gputask.h index dc863458..768d03c8 100644 --- a/dev/src/gputask.h +++ b/dev/src/gputask.h @@ -10,6 +10,7 @@ //! START CUSTOMHEADER #include "config.h" #include "pixel.h" +#include "image.h" #include "transform2d.h" //! END CUSTOMHEADER @@ -33,8 +34,12 @@ namespace olc struct Vertex { - float p[6]; // x, y, z, w, u, v + float p[4]; // x, y, z, w olc::Pixel c; // 32-bit colour + float t0[2]; + float t1[2]; + float t2[2]; + float t3[2]; }; // Simple vertex buffer @@ -57,6 +62,8 @@ namespace olc // Overall biasing colour (great for blends) olc::Pixel tint = olc::Colour::WHITE; + olc::Image* pImage = nullptr; + // Define super structure to be drawn enum class Structure : uint8_t { diff --git a/dev/src/window.cpp b/dev/src/window.cpp index af62fdb9..6b3e0d1a 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -82,8 +82,12 @@ namespace olc gpu->DisplayPrepare(); - gpu->SetViewport({ 0,0 }, GetSize()); + + + gpu->AssignTextureTarget(0, imgPrimary.GetGPUID()); + gpu->SetViewport({ 0,0 }, imgPrimary.Size()); gpu->ClearViewport(olc::Colour::BLACK, true, true); + gpu->ApplyDefaultShader(); // User Update @@ -97,9 +101,17 @@ namespace olc } } + // Finialise any outstanding tasks draw.ProcessGPUTasks(); + // Take the window's completed "screen" and draw it as a textured quad to the backbuffer + gpu->AssignTextureTarget(0, 0); + gpu->SetViewport({ 0,0 }, GetSize()); + gpu->ClearViewport(olc::Colour::TANGERINE, true, true); + draw.Image(imgPrimary, { -1.0,-1.0 }, { 2.0f,2.0f }); + draw.ProcessGPUTasks(); + // Update Window's primary surface gpu->DisplayDraw(); diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index bc2eb9e8..1f1445f3 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -22,9 +22,17 @@ class Example : public olc::PixelGameEngine { draw.Line({ 0,0 }, { 1, 1 }, olc::Colour::RED); draw.Line({ 0,0 }, { 1, -1 }, olc::Colour::GREEN); - draw.Line({ 0,0 }, { -1, -1 }, olc::Colour::BLUE); + draw.Line({ 0,0 }, { -1, -1 }, olc::Colour::CYAN); draw.Line({ 0,0 }, { -1, 1 }, olc::Colour::WHITE); + draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); + + draw.FillRect({ 0.25f, 0.25f }, { 0.3f, 0.6f }, olc::Colour::TANGERINE); + + draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); + draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); + draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); + return true; } }; From 016df9f63b955bef10392e275607a594569beed8 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 10 Sep 2025 22:23:39 +0100 Subject: [PATCH 06/11] Experimenting with Affines --- dev/src/config.h | 2 +- dev/src/draw2d.cpp | 81 +++++++++++++++++++++++++++++++++++++------ dev/src/draw2d.h | 16 +++++++-- dev/src/matrix3d.h | 12 +++++++ dev/src/transform2d.h | 7 ++++ dev/src/window.cpp | 2 +- dev/tests/test_mh.cpp | 56 +++++++++++++++++++++++++----- 7 files changed, 151 insertions(+), 25 deletions(-) diff --git a/dev/src/config.h b/dev/src/config.h index 3dafb34d..6b710af7 100644 --- a/dev/src/config.h +++ b/dev/src/config.h @@ -72,7 +72,7 @@ #define OLC_GPU_MAX_VERTICES 8192 -#define OLC_GPU_ERRORCHECK 1 +#define OLC_GPU_ERRORCHECK 0 #define LICENCE_DEFAULT "OneLoneCoder.com - Pixel Game Engine 3 - " diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index 23843b53..25daf374 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -16,22 +16,37 @@ void Draw2D::SetGPU(olc::gpu::Renderer* const renderer) void Draw2D::SetTarget(olc::Image& image) { - pTarget = ℑ + // Store the target image + pTarget = ℑ + + // Create a transform to denormalise the image and present it + // in pixel space + transformTarget.scale(olc::vf2d(2.0f, -2.0f) / olc::vf2d(pTarget->Size())); + transformTarget.translate( + olc::vf2d( + -1.0 + (1.0f / float(pTarget->Size().x)), + 1.0f - (1.0f / float(pTarget->Size().y)) + )); + + AffineReset(); + } void Draw2D::ClearTransform() { - transform = olc::tf2d(); + transformTarget = olc::tf2d(); + transformAffine = olc::tf2d(); + transformCombined = olc::mf3d(); } void Draw2D::SetTransform(const olc::tf2d& trans) { - transform = trans; + transformTarget = trans; } -const tf2d& olc::Draw2D::GetTransform() +tf2d& const olc::Draw2D::GetTransform() { - return transform; + return transformAffine; } void olc::Draw2D::ProcessGPUTasks() @@ -69,15 +84,46 @@ void Draw2D::PrepareTargetForHW() } } +void olc::Draw2D::AffineReset() +{ + transformAffine = olc::tf2d(); + transformCombined = transformAffine * transformTarget; +} + +void olc::Draw2D::AffineScale(const olc::vf2d& vScale) +{ + transformAffine.scale(vScale); + transformCombined = transformAffine * transformTarget; +} + +void olc::Draw2D::AffineOffset(const olc::vf2d& vOffset) +{ + transformAffine.translate(vOffset); + transformCombined = transformAffine * transformTarget; +} + +void olc::Draw2D::AffineRotate(const float& fTheta, const olc::vf2d& vPoint) +{ + transformAffine.rotate(fTheta, vPoint); + transformCombined = transformAffine * transformTarget; +} + void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { PrepareTargetForSW(); - pTarget->Data(transform.forward(((pos + 1.0f) * 0.5f) * olc::vf2d(pTarget->Size()))) = col; + pTarget->Data(transformTarget.forward(((pos + 1.0f) * 0.5f) * olc::vf2d(pTarget->Size()))) = col; } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) { - return GPUTask(); + GPUTask task; + task.structure = structure; + task.bWireframe = true; + for (size_t i = 0; i < vPoints.size(); i++) + task.vertexBuffer.push_back({ vPoints[i].x, vPoints[i].y, 1.0f, 1.0f, vColours[i], 0, 0, 0,0, 0, 0, 0, 0}); + //task.mvpMatrix = transformCombined.m + task.tint = tint; + return task; } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) @@ -122,7 +168,7 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel return vecGPUTasks.emplace_back( TaskDrawPolygon( GPUTask::Structure::Line, - transform.forward({ p1, p2 }), + transformCombined.transform({ p1, p2 }), col, olc::Colour::WHITE )); @@ -134,19 +180,32 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel return vecGPUTasks.emplace_back( TaskDrawPolygon( GPUTask::Structure::Line, - transform.forward({ p1, p2 }), + transformCombined.transform({ p1, p2 }), { c1, c2 }, olc::Colour::WHITE )); } +GPUTask olc::Draw2D::Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskDrawPolygon( + GPUTask::Structure::Fan, + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + col, + olc::Colour::WHITE + )); +} + + GPUTask olc::Draw2D::FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) { PrepareTargetForHW(); return vecGPUTasks.emplace_back( TaskFillPolygon( GPUTask::Structure::Fan, - transform.forward({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), col, olc::Colour::WHITE )); @@ -158,7 +217,7 @@ GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::v return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, - transform.forward({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, { {0,0}, {1,0}, {1,1}, {0,1} }, &image diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index 3b643b7a..66aa0b13 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -45,7 +45,7 @@ namespace olc void SetTransform(const olc::tf2d& trans); - const olc::tf2d& GetTransform(); + olc::tf2d& const GetTransform(); void ProcessGPUTasks(); @@ -57,10 +57,18 @@ namespace olc olc::Image* pTarget = nullptr; olc::gpu::Renderer* pRenderer = nullptr; - olc::tf2d transform; + olc::tf2d transformTarget; + olc::tf2d transformAffine; + olc::mf3d transformCombined; std::vector vecGPUTasks; + public: // Affine Transformation + void AffineReset(); + void AffineScale(const olc::vf2d& vScale); + void AffineOffset(const olc::vf2d& vOffset); + void AffineRotate(const float& fTheta, const olc::vf2d& vPoint = { 0,0 }); + public: // Plot a single pixel void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); @@ -107,9 +115,11 @@ namespace olc // Draws a single pixel wide line with a gradient GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + GPUTask Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + + // Draws a filled, single colour rectangle GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); - // Draws a filled, single colour rectangle GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); }; diff --git a/dev/src/matrix3d.h b/dev/src/matrix3d.h index 9e75f1c9..fa5c2dd5 100644 --- a/dev/src/matrix3d.h +++ b/dev/src/matrix3d.h @@ -194,6 +194,18 @@ namespace olc return out; } + + // Transform a vector of v_2d by this matrix + template + inline constexpr auto transform(const std::vector>& v) + { + std::vector> o(v.size()); + std::transform(v.begin(), v.end(), o.begin(), [this](const olc::v_2d& i) {return (*this) * i; }); + return o; + } + + + // Return this matrix as a std::string, of the form "[c1r1, c2r1, c3r1]\n[c1r2, c2r2, c3r2]\n[c1r3, c2r3, c3r3]" inline std::string str() const { diff --git a/dev/src/transform2d.h b/dev/src/transform2d.h index 90e4a82e..cfe7b561 100644 --- a/dev/src/transform2d.h +++ b/dev/src/transform2d.h @@ -185,6 +185,13 @@ namespace olc update(); } + template + inline constexpr auto operator * (const olc::t_2d& rhs) const + { + auto& me = *this; + return me.forward_matrix() * rhs.forward_matrix(); + } + protected: // Constructs resultant matrices when transformation changes inline constexpr void update() diff --git a/dev/src/window.cpp b/dev/src/window.cpp index 6b3e0d1a..444c993d 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -76,7 +76,6 @@ namespace olc { // Environmental changes - draw.ClearTransform(); draw.SetGPU(gpu); draw.SetTarget(imgPrimary); @@ -109,6 +108,7 @@ namespace olc gpu->AssignTextureTarget(0, 0); gpu->SetViewport({ 0,0 }, GetSize()); gpu->ClearViewport(olc::Colour::TANGERINE, true, true); + draw.ClearTransform(); draw.Image(imgPrimary, { -1.0,-1.0 }, { 2.0f,2.0f }); draw.ProcessGPUTasks(); diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index 1f1445f3..3316eab3 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -11,6 +11,8 @@ class Example : public olc::PixelGameEngine olc::Image imTest; + float fAngle = 0.0f; + public: bool OnUserCreate() override { @@ -20,18 +22,54 @@ class Example : public olc::PixelGameEngine bool OnUserUpdate(float fElapsedTime) override { - draw.Line({ 0,0 }, { 1, 1 }, olc::Colour::RED); - draw.Line({ 0,0 }, { 1, -1 }, olc::Colour::GREEN); - draw.Line({ 0,0 }, { -1, -1 }, olc::Colour::CYAN); - draw.Line({ 0,0 }, { -1, 1 }, olc::Colour::WHITE); + fAngle += fElapsedTime; + + //draw.AffineRotate(fAngle, { 128,120 }); + //draw.AffineOffset({ 10,10 }); + draw.AffineScale(olc::vf2d(1,1) * (std::sin(fAngle) + 1.1)); + + draw.Rect({ 0,0 }, GetSize() - olc::vf2d{1, 1}, olc::Colour::CYAN); + draw.FillRect({ 100.0f, 30.0f }, { 20.0f, 50.0f }, olc::Colour::TANGERINE); + + + + for (float i = 0; i < 20; i++) + { + draw.AffineRotate(fAngle + (i/50.0f), {128,120}); + if (fmod(i,2) == 1) + { + draw.Line({ 0 + i * 4 ,0 + i * 4 }, { 255 - i * 4, 0 + i * 4 }, olc::Colour::RED, olc::Colour::GREEN); + draw.Line({ 255 - i * 4,0 + i * 4 }, { 255 - i * 4, 239 - i * 4 }, olc::Colour::GREEN, olc::Colour::CYAN); + draw.Line({ 255 - i * 4,239 - i * 4 }, { 0 + i * 4, 239 - i * 4 }, olc::Colour::CYAN, olc::Colour::WHITE); + draw.Line({ 0 + i * 4,239 - i * 4 }, { 0 + i * 4, 0 + i * 4 }, olc::Colour::WHITE, olc::Colour::RED); + } + else + { + draw.Line({ 0 + i * 4 ,0 + i * 4 }, { 255 - i * 4, 0 + i * 4 }, olc::Colour::RED); + draw.Line({ 255 - i * 4,0 + i * 4 }, { 255 - i * 4, 239 - i * 4 }, olc::Colour::GREEN); + draw.Line({ 255 - i * 4,239 - i * 4 }, { 0 + i * 4, 239 - i * 4 }, olc::Colour::CYAN); + draw.Line({ 0 + i * 4,239 - i * 4 }, { 0 + i * 4, 0 + i * 4 }, olc::Colour::WHITE); + } + } + + /*for (int x = 0; x < 100; x++) + { + for (int y = 0; y < 100; y++) + { + if (x % 2 == 0) + { + draw.Pixel(olc::vf2d(x, y) + olc::vf2d(100, 100), olc::Colour::YELLOW); + } + } + }*/ - draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); + //draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); - draw.FillRect({ 0.25f, 0.25f }, { 0.3f, 0.6f }, olc::Colour::TANGERINE); + draw.FillRect({ 100.0f, 30.0f }, { 20.0f, 50.0f }, olc::Colour::TANGERINE); - draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); - draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); - draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); + //draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); + //draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); + //draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); return true; } From 915927b5ed00c40f69c58c6cc4fcc409df10e7e1 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Sun, 14 Sep 2025 16:56:53 +0100 Subject: [PATCH 07/11] Mouse, Scaling, Image Loading, Off-Screen Rendering, Sampling. All seems good so far lol --- dev/msvc/olcPGE3.vcxproj | 8 + dev/msvc/olcPGE3.vcxproj.filters | 24 + .../olcPGE3_BuildSH/olcPixelGameEngine3.h | 629 ++++++++++++++++-- dev/msvc/olcPGE3_BuildSH/test_sh.cpp | 50 +- dev/src/api_opengl.cpp | 6 + dev/src/api_opengl.h | 2 +- dev/src/config.h | 11 + dev/src/core.cpp | 31 +- dev/src/core.h | 4 +- dev/src/draw2d.cpp | 61 +- dev/src/draw2d.h | 46 +- dev/src/gpu_opengl33.cpp | 11 +- dev/src/host_win_winapi.cpp | 40 +- dev/src/hw_input.h | 26 + dev/src/hw_keyboard.h | 1 + dev/src/hw_mouse.cpp | 51 ++ dev/src/hw_mouse.h | 49 ++ dev/src/hw_touch.h | 1 + dev/src/image.cpp | 9 +- dev/src/image.h | 4 +- dev/src/imload_iface.h | 45 ++ dev/src/imload_wingdi.cpp | 90 +++ dev/src/imload_wingdi.h | 79 +++ dev/src/olcpge3.h | 5 + dev/src/sh_template.h | 25 + dev/src/window.cpp | 13 +- dev/src/window.h | 9 + dev/tests/test_mh.cpp | 136 ++-- 28 files changed, 1309 insertions(+), 157 deletions(-) create mode 100644 dev/src/hw_input.h create mode 100644 dev/src/hw_keyboard.h create mode 100644 dev/src/hw_mouse.cpp create mode 100644 dev/src/hw_mouse.h create mode 100644 dev/src/hw_touch.h create mode 100644 dev/src/imload_iface.h create mode 100644 dev/src/imload_wingdi.cpp create mode 100644 dev/src/imload_wingdi.h diff --git a/dev/msvc/olcPGE3.vcxproj b/dev/msvc/olcPGE3.vcxproj index 4f525342..75d91f2a 100644 --- a/dev/msvc/olcPGE3.vcxproj +++ b/dev/msvc/olcPGE3.vcxproj @@ -187,7 +187,13 @@ + + + + + + @@ -204,7 +210,9 @@ + + true diff --git a/dev/msvc/olcPGE3.vcxproj.filters b/dev/msvc/olcPGE3.vcxproj.filters index 03904b2f..08ebcaab 100644 --- a/dev/msvc/olcPGE3.vcxproj.filters +++ b/dev/msvc/olcPGE3.vcxproj.filters @@ -81,6 +81,24 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -122,5 +140,11 @@ Source Files + + Header Files + + + Source Files + \ No newline at end of file diff --git a/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h b/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h index c9f16ddf..6b5e2868 100644 --- a/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h +++ b/dev/msvc/olcPGE3_BuildSH/olcPixelGameEngine3.h @@ -23,6 +23,7 @@ #include #include #include +#include // Version number (accessible as value for incremental comparisons) #define PGE_VER 300 @@ -94,8 +95,19 @@ #endif + +#define OLC_IMAGELOADER_NONE 1 +#define OLC_IMAGELOADER_WINGDI 2 + +#if !defined(OLC_IMAGELOADER) + #define OLC_IMAGELOADER OLC_IMAGELOADER_WINGDI +#endif + + +#define OLC_MOUSE_BUTTONS 3 + #define OLC_GPU_MAX_VERTICES 8192 -#define OLC_GPU_ERRORCHECK 1 +#define OLC_GPU_ERRORCHECK 0 #define LICENCE_DEFAULT "OneLoneCoder.com - Pixel Game Engine 3 - " @@ -899,6 +911,18 @@ namespace olc return out; } + + // Transform a vector of v_2d by this matrix + template + inline constexpr auto transform(const std::vector>& v) + { + std::vector> o(v.size()); + std::transform(v.begin(), v.end(), o.begin(), [this](const olc::v_2d& i) {return (*this) * i; }); + return o; + } + + + // Return this matrix as a std::string, of the form "[c1r1, c2r1, c3r1]\n[c1r2, c2r2, c3r2]\n[c1r3, c2r3, c3r3]" inline std::string str() const { @@ -1094,6 +1118,13 @@ namespace olc update(); } + template + inline constexpr auto operator * (const olc::t_2d& rhs) const + { + auto& me = *this; + return me.forward_matrix() * rhs.forward_matrix(); + } + protected: // Constructs resultant matrices when transformation changes inline constexpr void update() @@ -1149,13 +1180,15 @@ namespace olc // Returns read/write pointer to start of 1D stream of pixel data olc::Pixel* Data(); // [UNSAFE] Returns pixel at location - olc::Pixel& Data(const olc::vf2d pos); + olc::Pixel& Pixel(const olc::vf2d& pos); // Returns how this image was configured upon creation const ImageConfig& GetConfig() const; // Return GPU Resource ID int32_t GetGPUID() const; // Set GPU Resource ID (0 to eliminate) void SetGPUID(const int32_t id); + // Get underlying vector of pixels + std::vector& GetPixels(); bool BoundToGPU() const; bool BoundToCPU() const; @@ -1175,6 +1208,38 @@ namespace olc } #define PGE_IMAGE_DECLARED 1 #endif + +#if !defined(PGE_IMAGELOADER_IFACE_DECLARED) +namespace olc +{ + namespace imload + { + class ImageLoader + { + public: + ImageLoader() = default; + virtual ~ImageLoader() = default; + + // Create an image resource based on an image file asset on disk + virtual bool CreateImageFromFile(olc::Image& image, const std::string& sFileName) = 0; + + // Create an image resource based on an image file asset in memory + virtual bool CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes) = 0; + + // Create an image resource based on an image file asset in memory + virtual bool CreateImageFromMemory(olc::Image& image, const std::vector& data) = 0; + + // Store an image as a file asset on disk + virtual bool WriteImageToFile(const olc::Image& image, const std::string& sFileName) = 0; + + // Store an image as a file asset in memory + virtual bool WriteImageToMemoryFile(olc::Image& image, const std::vector& data) = 0; + + }; + } +} +#define PGE_IMAGELOADER_IFACE_DECLARED 1 +#endif #if !defined(PGE_GPUTASK_DECLARED) namespace olc @@ -1426,7 +1491,7 @@ namespace olc void SetTransform(const olc::tf2d& trans); - const olc::tf2d& GetTransform(); + olc::tf2d& GetTransform(); void ProcessGPUTasks(); @@ -1436,18 +1501,49 @@ namespace olc // Checks residency of image resource, and brings it to gpu VRAM for r/w void PrepareTargetForHW(); + // Checks residency of image resource, and brings it to cpu RAM for r/w + void PrepareImageForSW(olc::Image& image); + // Checks residency of image resource, and brings it to gpu VRAM for r/w + void PrepareImageForHW(olc::Image& image); + olc::Image* pTarget = nullptr; olc::gpu::Renderer* pRenderer = nullptr; - olc::tf2d transform; + olc::tf2d transformTarget; + olc::tf2d transformAffine; + olc::mf3d transformCombined; std::vector vecGPUTasks; + public: // Affine Transformation (these affect all subsequent draw calls for this target) + void AffineReset(); + void AffineScale(const olc::vf2d& vScale); + void AffineOffset(const olc::vf2d& vOffset); + void AffineRotate(const float& fTheta, const olc::vf2d& vPoint = { 0,0 }); + public: // Plot a single pixel void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); + // Read a pixel from an image (guarantees fresh) + olc::Pixel GetPixel(olc::Image& image, const olc::vf2d& pos); + + public: + // Draws a single pixel wide line + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); + // Draws a single pixel wide line with a gradient + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + + // Draws a rectangle outline + GPUTask Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + // Draws a filled, single colour rectangle + GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + + // Draws an image + GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); + + - public: // GPU Task Creator Functions + public: // GPU Task Creator Functions (not normally called by user) GPUTask TaskDrawPolygon( GPUTask::Structure structure, const std::vector& vPoints, @@ -1479,23 +1575,63 @@ namespace olc const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint = olc::Colour::WHITE); + + }; +} +#define PGE_DRAW2D_DECLARED +#endif +#if !defined(PGE_HARDWAREINPUT_DECLARED) +namespace olc +{ + namespace hw + { + struct Button + { + bool bPressed = false; + bool bReleased = false; + bool bHeld = false; + }; + } +} +#define PGE_HARDWAREINPUT_DECLARED 1 +#endif +#if !defined(PGE_HW_MOUSE_DECLARED) +namespace olc +{ + // Forward declare for friendship + class Window; - public: - // Draws a single pixel wide line - GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); - // Draws a single pixel wide line with a gradient - GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); - // Draws a filled, single colour rectangle - GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + namespace hw + { + class Mouse + { + friend class olc::Window; - // Draws a filled, single colour rectangle - GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); - }; + public: + Mouse() = default; + + public: + const Button& GetButton(const int nButton) const; + const olc::vf2d& GetPosition() const; + + protected: + std::array buttons{}; + std::array buttons_new{}; + std::array buttons_old{}; + olc::vf2d position; + olc::vf2d position_in; + + private: + void SetPosition(const olc::vf2d& pos); + void SetButton(const int nButton, bool state); + void UpdateState(); + }; + } } -#define PGE_DRAW2D_DECLARED +#define PGE_HW_MOUSE_DECLARED 1 #endif #if !defined(PGE_WINDOW_DECLARED) @@ -1517,9 +1653,15 @@ namespace olc class Renderer; } + namespace hw + { + class Mouse; + } + class Window { friend class olc::host::FRIENDLY_HOST; + public: Window(); @@ -1588,6 +1730,8 @@ namespace olc protected: olc::Draw2D draw; olc::Image imgPrimary; + + olc::hw::Mouse mouse; }; } #define PGE_WINDOW_DECLARED 1 @@ -1716,7 +1860,7 @@ namespace olc // Store an image as a file asset on disk bool WriteImageToFile(const olc::Image& image, const std::string& sFileName); // Store an image as a file asset in memory - bool WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName); + //bool WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName); // Destroy an image void DestroyImage(olc::Image& image); @@ -1743,6 +1887,7 @@ namespace olc std::unique_ptr gpu; std::unique_ptr host; + std::unique_ptr imageloader; }; } #define PGE_CORE_DECLARED 1 @@ -1754,6 +1899,7 @@ namespace olc + #if OLC_HOST == OLC_HOST_WINDOWS #if defined(UNICODE) || defined(_UNICODE) #define olcT(s) L##s @@ -2028,7 +2174,7 @@ namespace olc void glDrawArrays(GLenum mode, GLint first, GLsizei count); void glBlendFunc(GLenum sfactor, GLenum dfactor); void glDepthFunc(GLenum func); - + void glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); private: @@ -2122,6 +2268,73 @@ namespace olc #endif #endif +#if OLC_IMAGELOADER == OLC_IMAGELOADER_WINGDI +#if defined(UNICODE) || defined(_UNICODE) + #define olcT(s) L##s +#else + #define olcT(s) s +#endif + +#define _WINSOCKAPI_ + +#if !defined(VC_EXTRALEAN) + #define VC_EXTRALEAN +#endif + +#if !defined(NOMINMAX) + #define NOMINMAX +#endif + +// In Code::Blocks +#if !defined(_WIN32_WINNT) + #ifdef HAVE_MSMF + #define _WIN32_WINNT 0x0600 // Windows Vista + #else + #define _WIN32_WINNT 0x0500 // Windows 2000 + #endif +#endif + +// Embrace MSVC superiority +#pragma comment(lib, "gdiplus.lib") +#pragma comment(lib, "Shlwapi.lib") +#include +#include +#include +#include +#undef _WINSOCKAPI_ + +#if !defined(PGE_IMAGELOADER_WINGDI_DECLARED) +namespace olc +{ + namespace imload + { + class ImageLoader_WinGDI : public ImageLoader + { + public: + + // Create an image resource based on an image file asset on disk + bool CreateImageFromFile(olc::Image& image, const std::string& sFileName) override; + + // Create an image resource based on an image file asset in memory + bool CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes) override; + + // Create an image resource based on an image file asset in memory + bool CreateImageFromMemory(olc::Image& image, const std::vector& data) override; + + // Store an image as a file asset on disk + bool WriteImageToFile(const olc::Image& image, const std::string& sFileName) override; + + // Store an image as a file asset in memory + bool WriteImageToMemoryFile(olc::Image& image, const std::vector& data) override; + + }; + } +} + +#define PGE_IMAGELOADER_WINGDI_DECLARED 1 +#endif +#endif + @@ -2333,12 +2546,36 @@ namespace olc::host // case WM_KEYUP: ptrPGE->olc_UpdateKeyState(int32_t(wParam), false); return 0; // case WM_SYSKEYDOWN: ptrPGE->olc_UpdateKeyState(int32_t(wParam), true); return 0; // case WM_SYSKEYUP: ptrPGE->olc_UpdateKeyState(int32_t(wParam), false); return 0; - // case WM_LBUTTONDOWN:ptrPGE->olc_UpdateMouseState(0, true); return 0; - // case WM_LBUTTONUP: ptrPGE->olc_UpdateMouseState(0, false); return 0; - // case WM_RBUTTONDOWN:ptrPGE->olc_UpdateMouseState(1, true); return 0; - // case WM_RBUTTONUP: ptrPGE->olc_UpdateMouseState(1, false); return 0; - // case WM_MBUTTONDOWN:ptrPGE->olc_UpdateMouseState(2, true); return 0; - // case WM_MBUTTONUP: ptrPGE->olc_UpdateMouseState(2, false); return 0; + case WM_LBUTTONDOWN: + { + window->olc_OnMouseButton(0, true); + return 0; + } + case WM_LBUTTONUP: + { + window->olc_OnMouseButton(0, false); + return 0; + } + case WM_RBUTTONDOWN: + { + window->olc_OnMouseButton(1, true); + return 0; + } + case WM_RBUTTONUP: + { + window->olc_OnMouseButton(1, false); + return 0; + } + case WM_MBUTTONDOWN: + { + window->olc_OnMouseButton(2, true); + return 0; + } + case WM_MBUTTONUP: + { + window->olc_OnMouseButton(2, false); + return 0; + } // case WM_DROPFILES: // { // // This is all eww... @@ -2612,6 +2849,12 @@ namespace olc::apis::opengl CheckError(); } + void gl::glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels) + { + ::glGetTexImage(target, level, format, type, pixels); + CheckError(); + } + GLuint gl::glCreateShader(GLenum type) { return _glCreateShader(type); @@ -2984,7 +3227,7 @@ namespace olc::gpu imgBlank.Create({ 1,1 }); imgBlank.SetGPUID(CreateTexture(imgBlank.Size())); imgBlank.BindCPU(); - imgBlank.Data({ 0,0 }) = olc::Colour::WHITE; + imgBlank.Pixel({ 0,0 }) = olc::Colour::WHITE; imgBlank.BindGPU(); WriteTexture(imgBlank.GetGPUID(), imgBlank); @@ -3002,7 +3245,8 @@ namespace olc::gpu // Unbind the FBO gl.glBindFramebuffer(36160U, 0); - + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); lastError = RendererError::None; return true; @@ -3071,7 +3315,8 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); gl.glBindTexture(GL_TEXTURE_2D, image.GetGPUID()); - gl.glReadPixels(0, 0, image.Size().x, image.Size().y, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); + //gl.glReadPixels(0, 0, image.Size().x, image.Size().y, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); + gl.glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); return true; } @@ -3134,6 +3379,8 @@ namespace olc::gpu { case GPUTask::Task::DrawPolygon: { + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (task.pImage == nullptr) AssignTextureSource(0, imgBlank.GetGPUID()); else @@ -3229,6 +3476,7 @@ namespace olc::gpu auto& gl = olc::apis::opengl::gl::Get(); //gl.glUseProgram(shaderDefault.GetShaderID()); + gl.glEnable(GL_BLEND); gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl.glDepthFunc(GL_LESS); //gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); @@ -3268,22 +3516,41 @@ void Draw2D::SetGPU(olc::gpu::Renderer* const renderer) void Draw2D::SetTarget(olc::Image& image) { - pTarget = ℑ + ProcessGPUTasks(); + + // Store the target image + pTarget = ℑ + + // Create a transform to denormalise the image and present it + // in pixel space + transformTarget.scale(olc::vf2d(2.0f, 2.0f) / olc::vf2d(pTarget->Size())); + transformTarget.translate( + olc::vf2d( + -1.0f + (1.0f / float(pTarget->Size().x)), + -1.0f + (1.0f / float(pTarget->Size().y)) + )); + + AffineReset(); + + pRenderer->AssignTextureTarget(0, pTarget->GetGPUID()); + pRenderer->SetViewport({ 0,0 }, pTarget->Size()); } void Draw2D::ClearTransform() { - transform = olc::tf2d(); + transformTarget = olc::tf2d(); + transformAffine = olc::tf2d(); + transformCombined = olc::mf3d(); } void Draw2D::SetTransform(const olc::tf2d& trans) { - transform = trans; + transformTarget = trans; } -const tf2d& olc::Draw2D::GetTransform() +tf2d& olc::Draw2D::GetTransform() { - return transform; + return transformAffine; } void olc::Draw2D::ProcessGPUTasks() @@ -3321,15 +3588,86 @@ void Draw2D::PrepareTargetForHW() } } +void Draw2D::PrepareImageForSW(olc::Image& image) +{ + if (image.BoundToGPU()) + { + // Process GPU queue bound for the target + ProcessGPUTasks(); + + // Image resource is primed for GPU operations, bring it to CPU + pRenderer->ReadTexture(image.GetGPUID(), image); + + // Image is now CPU bound + image.BindCPU(); + } +} + +void Draw2D::PrepareImageForHW(olc::Image& image) +{ + if (image.BoundToCPU()) + { + // Image resource is primed for CPU operations, send it to GPU + pRenderer->WriteTexture(image.GetGPUID(), image); + + // Image is now GPU bound + image.BindGPU(); + } +} + +void olc::Draw2D::AffineReset() +{ + transformAffine = olc::tf2d(); + transformCombined = transformAffine * transformTarget; +} + +void olc::Draw2D::AffineScale(const olc::vf2d& vScale) +{ + transformAffine.scale(vScale); + transformCombined = transformAffine * transformTarget; +} + +void olc::Draw2D::AffineOffset(const olc::vf2d& vOffset) +{ + transformAffine.translate(vOffset); + transformCombined = transformAffine * transformTarget; +} + +void olc::Draw2D::AffineRotate(const float& fTheta, const olc::vf2d& vPoint) +{ + transformAffine.rotate(fTheta, vPoint); + transformCombined = transformAffine * transformTarget; +} + void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { - PrepareTargetForSW(); - pTarget->Data(transform.forward(((pos + 1.0f) * 0.5f) * olc::vf2d(pTarget->Size()))) = col; + // Check if in bounds + olc::vf2d tpos = transformTarget.forward(pos); + if (tpos.x >= 0 && tpos.y >= 0 && tpos.x < pTarget->Size().x && tpos.y < pTarget->Size().y) + { + PrepareTargetForSW(); + pTarget->Pixel(tpos) = col; + } + + // otherwise do nothing +} + +olc::Pixel olc::Draw2D::GetPixel(olc::Image& image, const olc::vf2d& pos) +{ + PrepareImageForSW(image); + return image.Pixel(pos); } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) { - return GPUTask(); + GPUTask task; + task.structure = structure; + task.bWireframe = true; + for (size_t i = 0; i < vPoints.size(); i++) + task.vertexBuffer.push_back({ vPoints[i].x, vPoints[i].y, 1.0f, 1.0f, vColours[i], 0, 0, 0,0, 0, 0, 0, 0}); + //task.mvpMatrix = transformCombined.m + task.tint = tint; + return task; } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const olc::Pixel colour, const olc::Pixel tint) @@ -3374,7 +3712,7 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel return vecGPUTasks.emplace_back( TaskDrawPolygon( GPUTask::Structure::Line, - transform.forward({ p1, p2 }), + transformCombined.transform({ p1, p2 }), col, olc::Colour::WHITE )); @@ -3386,19 +3724,32 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel return vecGPUTasks.emplace_back( TaskDrawPolygon( GPUTask::Structure::Line, - transform.forward({ p1, p2 }), + transformCombined.transform({ p1, p2 }), { c1, c2 }, olc::Colour::WHITE )); } +GPUTask olc::Draw2D::Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) +{ + PrepareTargetForHW(); + return vecGPUTasks.emplace_back( + TaskDrawPolygon( + GPUTask::Structure::Fan, + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + col, + olc::Colour::WHITE + )); +} + + GPUTask olc::Draw2D::FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) { PrepareTargetForHW(); return vecGPUTasks.emplace_back( TaskFillPolygon( GPUTask::Structure::Fan, - transform.forward({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), col, olc::Colour::WHITE )); @@ -3406,11 +3757,14 @@ GPUTask olc::Draw2D::FillRect(const olc::vf2d& pos, const olc::vf2d& size, const GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size) { + // Ensure source image is up to date in VRAM + PrepareImageForHW(image); + PrepareTargetForHW(); return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, - transform.forward({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, { {0,0}, {1,0}, {1,1}, {0,1} }, &image @@ -3506,7 +3860,24 @@ namespace olc } bool PixelGameEngine::CreateImageFromFile(olc::Image& image, const std::string& sFileName, const ImageConfig& cfg) - { + { + if (imageloader->CreateImageFromFile(image, sFileName)) + { + // Image has loaded ok, and populated into pixel vector + // + // Create GPU Image + auto id = gpu->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.Create({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + return false; } @@ -3520,10 +3891,10 @@ namespace olc return false; } - bool PixelGameEngine::WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName) - { - return false; - } + //bool PixelGameEngine::WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName) + //{ + // return false; + //} void PixelGameEngine::DestroyImage(olc::Image& image) { @@ -3549,6 +3920,9 @@ namespace olc using namespace std::chrono_literals; timeFrame2 = std::chrono::steady_clock::now(); timeFrame1 = std::chrono::steady_clock::now(); + + // Initialise ImageLoader Interface + imageloader = std::make_unique(); // Initialise GPU Interface - This thread is the context @@ -3685,9 +4059,9 @@ namespace olc return pixels.data(); } - olc::Pixel& Image::Data(const olc::vf2d pos) + olc::Pixel& Image::Pixel(const olc::vf2d& pos) { - return pixels[pos.y * dimensions.x + pos.x]; + return pixels[int(pos.y) * dimensions.x + int(pos.x)]; } const ImageConfig& Image::GetConfig() const @@ -3705,6 +4079,11 @@ namespace olc gpuResourceID = id; } + std::vector& Image::GetPixels() + { + return pixels; + } + bool Image::BoundToGPU() const { return onGPU; @@ -3731,6 +4110,57 @@ namespace olc #define PGE_IMAGE_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_HW_MOUSE_IMPLEMENTED) +namespace olc::hw +{ + const Button& Mouse::GetButton(const int nButton) const + { + return buttons.at(nButton); + } + + const olc::vf2d& Mouse::GetPosition() const + { + return position; + } + + void Mouse::SetPosition(const olc::vf2d& pos) + { + position_in = pos; + } + + void Mouse::SetButton(const int nButton, bool state) + { + buttons_new[nButton] = state; + } + + void Mouse::UpdateState() + { + for (size_t i=0; iAssignTextureTarget(0, 0); gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::TANGERINE, true, true); - draw.Image(imgPrimary, { -1.0,-1.0 }, { 2.0f,2.0f }); + gpu->ClearViewport(olc::Colour::BLANK, true, true); + draw.ClearTransform(); + draw.Image(imgPrimary, { -1.0,1.0 }, { 2.0f,-2.0f }); draw.ProcessGPUTasks(); // Update Window's primary surface @@ -3898,3 +4333,95 @@ namespace olc #define PGE_WINDOW_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_IMAGELOADER_IMPLEMENTED) +#if OLC_IMAGELOADER == OLC_IMAGELOADER_WINGDI +namespace olc::imload +{ + namespace internals + { + std::wstring ConvertS2W(std::string s) + { +#ifdef __MINGW32__ + wchar_t* buffer = new wchar_t[s.length() + 1]; + mbstowcs(buffer, s.c_str(), s.length()); + buffer[s.length()] = L'\0'; +#else + int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + wchar_t* buffer = new wchar_t[count]; + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); +#endif + std::wstring w(buffer); + delete[] buffer; + return w; + } + + static class GDIPlusStartup + { + public: + GDIPlusStartup() + { + Gdiplus::GdiplusStartupInput startupInput; + GdiplusStartup(&token, &startupInput, NULL); + } + + ULONG_PTR token; + + ~GDIPlusStartup() + { + Gdiplus::GdiplusShutdown(token); + } + + } gdistartup; + } + + bool ImageLoader_WinGDI::CreateImageFromFile(olc::Image& image, const std::string& sFileName) + { + // Check file exists + if (!std::filesystem::exists(sFileName)) + return false; // File doesn't exist + + // Load file into windows "bitmap". 1992 calling... + Gdiplus::Bitmap* bmp = nullptr; + bmp = Gdiplus::Bitmap::FromFile(internals::ConvertS2W(sFileName).c_str()); + if (bmp->GetLastStatus() != Gdiplus::Ok) + return false; // File wasn't valid + + // Need to swizzle each pixel... + image.Create(olc::vi2d(bmp->GetWidth(), bmp->GetHeight())); + for (int y = 0; y < image.Size().y; y++) + for (int x = 0; x < image.Size().x; x++) + { + Gdiplus::Color c; + bmp->GetPixel(x, y, &c); + image.Pixel(olc::vi2d(x, y)) = olc::Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha()); + } + + // All done + delete bmp; + return true; + } + + bool ImageLoader_WinGDI::CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes) + { + return false; + } + + bool ImageLoader_WinGDI::CreateImageFromMemory(olc::Image& image, const std::vector& data) + { + return false; + } + + bool ImageLoader_WinGDI::WriteImageToFile(const olc::Image& image, const std::string& sFileName) + { + return false; + } + + bool ImageLoader_WinGDI::WriteImageToMemoryFile(olc::Image& image, const std::vector& data) + { + return false; + } +} +#endif +#define PGE_IMAGELOADER_IMPLEMENTED 1 +#endif + diff --git a/dev/msvc/olcPGE3_BuildSH/test_sh.cpp b/dev/msvc/olcPGE3_BuildSH/test_sh.cpp index 88744338..2b7e2170 100644 --- a/dev/msvc/olcPGE3_BuildSH/test_sh.cpp +++ b/dev/msvc/olcPGE3_BuildSH/test_sh.cpp @@ -9,26 +9,58 @@ class Example : public olc::PixelGameEngine } + olc::Image imTest; + + olc::Image sprite1; + + float fAngle = 0.0f; + public: bool OnUserCreate() override { + CreateImage(imTest, { 64,64 }); + CreateImageFromFile(sprite1, "E:/assets/Graphics/Tiles_SideOn/HiQ/FactoryPack/png/256/objects/static/Computer (1).png"); + return true; } bool OnUserUpdate(float fElapsedTime) override { - draw.Line({ 0,0 }, { 1, 1 }, olc::Colour::RED); - draw.Line({ 0,0 }, { 1, -1 }, olc::Colour::GREEN); - draw.Line({ 0,0 }, { -1, -1 }, olc::Colour::CYAN); - draw.Line({ 0,0 }, { -1, 1 }, olc::Colour::WHITE); + fAngle += fElapsedTime; + + + + + draw.SetTarget(imTest); + draw.FillRect({ 0,0 }, imTest.Size(), olc::Colour::BLUE); + + draw.AffineRotate(fAngle, { 32.0f, 32.0f }); + + draw.Rect({ 5,5 }, { 10,10 }, olc::Colour::YELLOW); + draw.Line({ 0,0 }, { 20, 20 }); + + + draw.SetTarget(imgPrimary); + draw.AffineReset(); + + draw.FillRect({ 0,0 }, imgPrimary.Size(), olc::Colour::VERY_DARK_MAGENTA); + + draw.Line({ 0,0 }, imgPrimary.Size() - 1, olc::Colour::RED); + draw.Line(olc::vf2d(imgPrimary.Size().x - 1, 0), olc::vf2d(0, imgPrimary.Size().y - 1), olc::Colour::GREEN); + + if (mouse.GetButton(0).bHeld) + draw.Line({ 0,0 }, mouse.GetPosition(), olc::Colour::TANGERINE); - draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); + draw.AffineRotate(fAngle * 0.2f, imgPrimary.Size() * 0.5f); + draw.Rect({ 0,0 }, imgPrimary.Size()); + draw.Image(imTest, { 10, 10 }, { 64, 64 }); + draw.Image(imTest, { 100, 10 }, { 64, 64 }); + draw.Image(imTest, { 10, 100 }, { 64, 64 }); + draw.Image(sprite1, { 100, 100 }, { 64, 64 }); - draw.FillRect({ 0.25f, 0.25f }, { 0.3f, 0.6f }, olc::Colour::TANGERINE); + olc::Pixel p = draw.GetPixel(imTest, { 8,5 }); - draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); - draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); - draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); + draw.FillRect({ 200,200 }, { 10,10 }, p); return true; } }; diff --git a/dev/src/api_opengl.cpp b/dev/src/api_opengl.cpp index 37537e7e..6d254174 100644 --- a/dev/src/api_opengl.cpp +++ b/dev/src/api_opengl.cpp @@ -189,6 +189,12 @@ namespace olc::apis::opengl CheckError(); } + void gl::glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels) + { + ::glGetTexImage(target, level, format, type, pixels); + CheckError(); + } + GLuint gl::glCreateShader(GLenum type) { return _glCreateShader(type); diff --git a/dev/src/api_opengl.h b/dev/src/api_opengl.h index bfc94d9f..13b36ea8 100644 --- a/dev/src/api_opengl.h +++ b/dev/src/api_opengl.h @@ -212,7 +212,7 @@ namespace olc void glDrawArrays(GLenum mode, GLint first, GLsizei count); void glBlendFunc(GLenum sfactor, GLenum dfactor); void glDepthFunc(GLenum func); - + void glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels); private: diff --git a/dev/src/config.h b/dev/src/config.h index 6b710af7..93ec4638 100644 --- a/dev/src/config.h +++ b/dev/src/config.h @@ -71,6 +71,17 @@ #endif + +#define OLC_IMAGELOADER_NONE 1 +#define OLC_IMAGELOADER_WINGDI 2 + +#if !defined(OLC_IMAGELOADER) + #define OLC_IMAGELOADER OLC_IMAGELOADER_WINGDI +#endif + + +#define OLC_MOUSE_BUTTONS 3 + #define OLC_GPU_MAX_VERTICES 8192 #define OLC_GPU_ERRORCHECK 0 diff --git a/dev/src/core.cpp b/dev/src/core.cpp index 93dbdd22..2a5e204c 100644 --- a/dev/src/core.cpp +++ b/dev/src/core.cpp @@ -2,6 +2,7 @@ #include "gpu_opengl33.h" #include "host_win_winapi.h" +#include "imload_wingdi.h" //! START IMPLEMENTATION namespace olc @@ -88,7 +89,24 @@ namespace olc } bool PixelGameEngine::CreateImageFromFile(olc::Image& image, const std::string& sFileName, const ImageConfig& cfg) - { + { + if (imageloader->CreateImageFromFile(image, sFileName)) + { + // Image has loaded ok, and populated into pixel vector + // + // Create GPU Image + auto id = gpu->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.Create({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + return false; } @@ -102,10 +120,10 @@ namespace olc return false; } - bool PixelGameEngine::WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName) - { - return false; - } + //bool PixelGameEngine::WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName) + //{ + // return false; + //} void PixelGameEngine::DestroyImage(olc::Image& image) { @@ -131,6 +149,9 @@ namespace olc using namespace std::chrono_literals; timeFrame2 = std::chrono::steady_clock::now(); timeFrame1 = std::chrono::steady_clock::now(); + + // Initialise ImageLoader Interface + imageloader = std::make_unique(); // Initialise GPU Interface - This thread is the context diff --git a/dev/src/core.h b/dev/src/core.h index d75429b7..2bdc9b14 100644 --- a/dev/src/core.h +++ b/dev/src/core.h @@ -19,6 +19,7 @@ #include "window.h" #include "gpu_iface.h" #include "host_iface.h" +#include "imload_iface.h" //! END CUSTOMHEADER GLOBAL //! START DECLARATION @@ -84,7 +85,7 @@ namespace olc // Store an image as a file asset on disk bool WriteImageToFile(const olc::Image& image, const std::string& sFileName); // Store an image as a file asset in memory - bool WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName); + //bool WriteImageToMemory(const olc::Image& image, std::vector bytes, const std::string& sFileName); // Destroy an image void DestroyImage(olc::Image& image); @@ -111,6 +112,7 @@ namespace olc std::unique_ptr gpu; std::unique_ptr host; + std::unique_ptr imageloader; }; } #define PGE_CORE_DECLARED 1 diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index 25daf374..905f3435 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -16,20 +16,24 @@ void Draw2D::SetGPU(olc::gpu::Renderer* const renderer) void Draw2D::SetTarget(olc::Image& image) { + ProcessGPUTasks(); + // Store the target image pTarget = ℑ // Create a transform to denormalise the image and present it // in pixel space - transformTarget.scale(olc::vf2d(2.0f, -2.0f) / olc::vf2d(pTarget->Size())); + transformTarget.scale(olc::vf2d(2.0f, 2.0f) / olc::vf2d(pTarget->Size())); transformTarget.translate( olc::vf2d( - -1.0 + (1.0f / float(pTarget->Size().x)), - 1.0f - (1.0f / float(pTarget->Size().y)) + -1.0f + (1.0f / float(pTarget->Size().x)), + -1.0f + (1.0f / float(pTarget->Size().y)) )); AffineReset(); - + + pRenderer->AssignTextureTarget(0, pTarget->GetGPUID()); + pRenderer->SetViewport({ 0,0 }, pTarget->Size()); } void Draw2D::ClearTransform() @@ -44,7 +48,7 @@ void Draw2D::SetTransform(const olc::tf2d& trans) transformTarget = trans; } -tf2d& const olc::Draw2D::GetTransform() +tf2d& olc::Draw2D::GetTransform() { return transformAffine; } @@ -84,6 +88,33 @@ void Draw2D::PrepareTargetForHW() } } +void Draw2D::PrepareImageForSW(olc::Image& image) +{ + if (image.BoundToGPU()) + { + // Process GPU queue bound for the target + ProcessGPUTasks(); + + // Image resource is primed for GPU operations, bring it to CPU + pRenderer->ReadTexture(image.GetGPUID(), image); + + // Image is now CPU bound + image.BindCPU(); + } +} + +void Draw2D::PrepareImageForHW(olc::Image& image) +{ + if (image.BoundToCPU()) + { + // Image resource is primed for CPU operations, send it to GPU + pRenderer->WriteTexture(image.GetGPUID(), image); + + // Image is now GPU bound + image.BindGPU(); + } +} + void olc::Draw2D::AffineReset() { transformAffine = olc::tf2d(); @@ -110,8 +141,21 @@ void olc::Draw2D::AffineRotate(const float& fTheta, const olc::vf2d& vPoint) void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { - PrepareTargetForSW(); - pTarget->Data(transformTarget.forward(((pos + 1.0f) * 0.5f) * olc::vf2d(pTarget->Size()))) = col; + // Check if in bounds + olc::vf2d tpos = transformTarget.forward(pos); + if (tpos.x >= 0 && tpos.y >= 0 && tpos.x < pTarget->Size().x && tpos.y < pTarget->Size().y) + { + PrepareTargetForSW(); + pTarget->Pixel(tpos) = col; + } + + // otherwise do nothing +} + +olc::Pixel olc::Draw2D::GetPixel(olc::Image& image, const olc::vf2d& pos) +{ + PrepareImageForSW(image); + return image.Pixel(pos); } GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) @@ -213,6 +257,9 @@ GPUTask olc::Draw2D::FillRect(const olc::vf2d& pos, const olc::vf2d& size, const GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size) { + // Ensure source image is up to date in VRAM + PrepareImageForHW(image); + PrepareTargetForHW(); return vecGPUTasks.emplace_back( TaskTexturedPolygon( diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index 66aa0b13..d57602d2 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -45,7 +45,7 @@ namespace olc void SetTransform(const olc::tf2d& trans); - olc::tf2d& const GetTransform(); + olc::tf2d& GetTransform(); void ProcessGPUTasks(); @@ -55,6 +55,11 @@ namespace olc // Checks residency of image resource, and brings it to gpu VRAM for r/w void PrepareTargetForHW(); + // Checks residency of image resource, and brings it to cpu RAM for r/w + void PrepareImageForSW(olc::Image& image); + // Checks residency of image resource, and brings it to gpu VRAM for r/w + void PrepareImageForHW(olc::Image& image); + olc::Image* pTarget = nullptr; olc::gpu::Renderer* pRenderer = nullptr; olc::tf2d transformTarget; @@ -63,7 +68,7 @@ namespace olc std::vector vecGPUTasks; - public: // Affine Transformation + public: // Affine Transformation (these affect all subsequent draw calls for this target) void AffineReset(); void AffineScale(const olc::vf2d& vScale); void AffineOffset(const olc::vf2d& vOffset); @@ -72,9 +77,27 @@ namespace olc public: // Plot a single pixel void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); + // Read a pixel from an image (guarantees fresh) + olc::Pixel GetPixel(olc::Image& image, const olc::vf2d& pos); + + public: + // Draws a single pixel wide line + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); + // Draws a single pixel wide line with a gradient + GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + + // Draws a rectangle outline + GPUTask Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + // Draws a filled, single colour rectangle + GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + + // Draws an image + GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); + - public: // GPU Task Creator Functions + + public: // GPU Task Creator Functions (not normally called by user) GPUTask TaskDrawPolygon( GPUTask::Structure structure, const std::vector& vPoints, @@ -106,22 +129,7 @@ namespace olc const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint = olc::Colour::WHITE); - - - - public: - // Draws a single pixel wide line - GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); - // Draws a single pixel wide line with a gradient - GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); - - GPUTask Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); - - - // Draws a filled, single colour rectangle - GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); - // Draws a filled, single colour rectangle - GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); + }; } #define PGE_DRAW2D_DECLARED diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index 1c957d53..698247de 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -191,7 +191,7 @@ namespace olc::gpu imgBlank.Create({ 1,1 }); imgBlank.SetGPUID(CreateTexture(imgBlank.Size())); imgBlank.BindCPU(); - imgBlank.Data({ 0,0 }) = olc::Colour::WHITE; + imgBlank.Pixel({ 0,0 }) = olc::Colour::WHITE; imgBlank.BindGPU(); WriteTexture(imgBlank.GetGPUID(), imgBlank); @@ -209,7 +209,8 @@ namespace olc::gpu // Unbind the FBO gl.glBindFramebuffer(36160U, 0); - + glEnable(GL_TEXTURE_2D); // Turn on texturing + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); lastError = RendererError::None; return true; @@ -278,7 +279,8 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); gl.glBindTexture(GL_TEXTURE_2D, image.GetGPUID()); - gl.glReadPixels(0, 0, image.Size().x, image.Size().y, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); + //gl.glReadPixels(0, 0, image.Size().x, image.Size().y, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); + gl.glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.Data()); return true; } @@ -341,6 +343,8 @@ namespace olc::gpu { case GPUTask::Task::DrawPolygon: { + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (task.pImage == nullptr) AssignTextureSource(0, imgBlank.GetGPUID()); else @@ -436,6 +440,7 @@ namespace olc::gpu auto& gl = olc::apis::opengl::gl::Get(); //gl.glUseProgram(shaderDefault.GetShaderID()); + gl.glEnable(GL_BLEND); gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl.glDepthFunc(GL_LESS); //gl.glBindTexture(GL_TEXTURE_2D, imgBlank.GetGPUID()); diff --git a/dev/src/host_win_winapi.cpp b/dev/src/host_win_winapi.cpp index 06be24e8..faa444af 100644 --- a/dev/src/host_win_winapi.cpp +++ b/dev/src/host_win_winapi.cpp @@ -110,12 +110,14 @@ namespace olc::host AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); int width = rWndRect.right - rWndRect.left; int height = rWndRect.bottom - rWndRect.top; - pWindow->SetSize({width, height}); + pWindow->SetSize(vWindowSize); // Create the actual OS window, return a handle HWND hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE3"), olcT(""), dwStyle, vTopLeft.x, vTopLeft.y, width, height, NULL, NULL, GetModuleHandle(nullptr), this); + SetWindowPos(hWnd, NULL, vWinPos.x, vWinPos.y, width, height, SWP_SHOWWINDOW); + // Now... awkwardly, the above has already fired off some window messages // and they arent necessarily in a consistent order. Whereas one might // assume WM_CREATE would be the first, there are some others on more @@ -203,12 +205,36 @@ namespace olc::host // case WM_KEYUP: ptrPGE->olc_UpdateKeyState(int32_t(wParam), false); return 0; // case WM_SYSKEYDOWN: ptrPGE->olc_UpdateKeyState(int32_t(wParam), true); return 0; // case WM_SYSKEYUP: ptrPGE->olc_UpdateKeyState(int32_t(wParam), false); return 0; - // case WM_LBUTTONDOWN:ptrPGE->olc_UpdateMouseState(0, true); return 0; - // case WM_LBUTTONUP: ptrPGE->olc_UpdateMouseState(0, false); return 0; - // case WM_RBUTTONDOWN:ptrPGE->olc_UpdateMouseState(1, true); return 0; - // case WM_RBUTTONUP: ptrPGE->olc_UpdateMouseState(1, false); return 0; - // case WM_MBUTTONDOWN:ptrPGE->olc_UpdateMouseState(2, true); return 0; - // case WM_MBUTTONUP: ptrPGE->olc_UpdateMouseState(2, false); return 0; + case WM_LBUTTONDOWN: + { + window->olc_OnMouseButton(0, true); + return 0; + } + case WM_LBUTTONUP: + { + window->olc_OnMouseButton(0, false); + return 0; + } + case WM_RBUTTONDOWN: + { + window->olc_OnMouseButton(1, true); + return 0; + } + case WM_RBUTTONUP: + { + window->olc_OnMouseButton(1, false); + return 0; + } + case WM_MBUTTONDOWN: + { + window->olc_OnMouseButton(2, true); + return 0; + } + case WM_MBUTTONUP: + { + window->olc_OnMouseButton(2, false); + return 0; + } // case WM_DROPFILES: // { // // This is all eww... diff --git a/dev/src/hw_input.h b/dev/src/hw_input.h new file mode 100644 index 00000000..e65f5e32 --- /dev/null +++ b/dev/src/hw_input.h @@ -0,0 +1,26 @@ +#pragma once + +//! START STDHEADER + +//! END STDHEADER + +//! START CUSTOMHEADER + +//! END CUSTOMHEADER + +//! START DECLARATION +#if !defined(PGE_HARDWAREINPUT_DECLARED) +namespace olc +{ + namespace hw + { + struct Button + { + bool bPressed = false; + bool bReleased = false; + bool bHeld = false; + }; + } +} +#define PGE_HARDWAREINPUT_DECLARED 1 +#endif diff --git a/dev/src/hw_keyboard.h b/dev/src/hw_keyboard.h new file mode 100644 index 00000000..6f70f09b --- /dev/null +++ b/dev/src/hw_keyboard.h @@ -0,0 +1 @@ +#pragma once diff --git a/dev/src/hw_mouse.cpp b/dev/src/hw_mouse.cpp new file mode 100644 index 00000000..bf2af5c6 --- /dev/null +++ b/dev/src/hw_mouse.cpp @@ -0,0 +1,51 @@ +#include "hw_mouse.h" + +//! START IMPLEMENTATION +namespace olc::hw +{ + const Button& Mouse::GetButton(const int nButton) const + { + return buttons.at(nButton); + } + + const olc::vf2d& Mouse::GetPosition() const + { + return position; + } + + void Mouse::SetPosition(const olc::vf2d& pos) + { + position_in = pos; + } + + void Mouse::SetButton(const int nButton, bool state) + { + buttons_new[nButton] = state; + } + + void Mouse::UpdateState() + { + for (size_t i=0; i +//! END STDHEADER + +//! START CUSTOMHEADER +#include "config.h" +#include "hw_input.h" +#include "vector2d.h" +//! END CUSTOMHEADER + +//! START DECLARATION +#if !defined(PGE_HW_MOUSE_DECLARED) +namespace olc +{ + // Forward declare for friendship + class Window; + + + namespace hw + { + class Mouse + { + friend class olc::Window; + + public: + Mouse() = default; + + public: + const Button& GetButton(const int nButton) const; + const olc::vf2d& GetPosition() const; + + protected: + std::array buttons{}; + std::array buttons_new{}; + std::array buttons_old{}; + olc::vf2d position; + olc::vf2d position_in; + + private: + void SetPosition(const olc::vf2d& pos); + void SetButton(const int nButton, bool state); + void UpdateState(); + }; + } +} +#define PGE_HW_MOUSE_DECLARED 1 +#endif diff --git a/dev/src/hw_touch.h b/dev/src/hw_touch.h new file mode 100644 index 00000000..6f70f09b --- /dev/null +++ b/dev/src/hw_touch.h @@ -0,0 +1 @@ +#pragma once diff --git a/dev/src/image.cpp b/dev/src/image.cpp index e774c8e4..2c528b96 100644 --- a/dev/src/image.cpp +++ b/dev/src/image.cpp @@ -29,9 +29,9 @@ namespace olc return pixels.data(); } - olc::Pixel& Image::Data(const olc::vf2d pos) + olc::Pixel& Image::Pixel(const olc::vf2d& pos) { - return pixels[pos.y * dimensions.x + pos.x]; + return pixels[int(pos.y) * dimensions.x + int(pos.x)]; } const ImageConfig& Image::GetConfig() const @@ -49,6 +49,11 @@ namespace olc gpuResourceID = id; } + std::vector& Image::GetPixels() + { + return pixels; + } + bool Image::BoundToGPU() const { return onGPU; diff --git a/dev/src/image.h b/dev/src/image.h index 95337ece..72bf441f 100644 --- a/dev/src/image.h +++ b/dev/src/image.h @@ -43,13 +43,15 @@ namespace olc // Returns read/write pointer to start of 1D stream of pixel data olc::Pixel* Data(); // [UNSAFE] Returns pixel at location - olc::Pixel& Data(const olc::vf2d pos); + olc::Pixel& Pixel(const olc::vf2d& pos); // Returns how this image was configured upon creation const ImageConfig& GetConfig() const; // Return GPU Resource ID int32_t GetGPUID() const; // Set GPU Resource ID (0 to eliminate) void SetGPUID(const int32_t id); + // Get underlying vector of pixels + std::vector& GetPixels(); bool BoundToGPU() const; bool BoundToCPU() const; diff --git a/dev/src/imload_iface.h b/dev/src/imload_iface.h new file mode 100644 index 00000000..8e22b45d --- /dev/null +++ b/dev/src/imload_iface.h @@ -0,0 +1,45 @@ +#pragma once + +//! START STDHEADER GLOBAL +#include +#include +//! END STDHEADER + +//! START CUSTOMHEADER +#include "config.h" +#include "image.h" +//! END CUSTOMHEADER + +//! START DECLARATION +#if !defined(PGE_IMAGELOADER_IFACE_DECLARED) +namespace olc +{ + namespace imload + { + class ImageLoader + { + public: + ImageLoader() = default; + virtual ~ImageLoader() = default; + + // Create an image resource based on an image file asset on disk + virtual bool CreateImageFromFile(olc::Image& image, const std::string& sFileName) = 0; + + // Create an image resource based on an image file asset in memory + virtual bool CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes) = 0; + + // Create an image resource based on an image file asset in memory + virtual bool CreateImageFromMemory(olc::Image& image, const std::vector& data) = 0; + + // Store an image as a file asset on disk + virtual bool WriteImageToFile(const olc::Image& image, const std::string& sFileName) = 0; + + // Store an image as a file asset in memory + virtual bool WriteImageToMemoryFile(olc::Image& image, const std::vector& data) = 0; + + }; + } +} +#define PGE_IMAGELOADER_IFACE_DECLARED 1 +#endif +//! END DECLARATION \ No newline at end of file diff --git a/dev/src/imload_wingdi.cpp b/dev/src/imload_wingdi.cpp new file mode 100644 index 00000000..5f2d5856 --- /dev/null +++ b/dev/src/imload_wingdi.cpp @@ -0,0 +1,90 @@ +#include "imload_wingdi.h" + +//! START IMPLEMENTATION +namespace olc::imload +{ + namespace internals + { + std::wstring ConvertS2W(std::string s) + { +#ifdef __MINGW32__ + wchar_t* buffer = new wchar_t[s.length() + 1]; + mbstowcs(buffer, s.c_str(), s.length()); + buffer[s.length()] = L'\0'; +#else + int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + wchar_t* buffer = new wchar_t[count]; + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); +#endif + std::wstring w(buffer); + delete[] buffer; + return w; + } + + static class GDIPlusStartup + { + public: + GDIPlusStartup() + { + Gdiplus::GdiplusStartupInput startupInput; + GdiplusStartup(&token, &startupInput, NULL); + } + + ULONG_PTR token; + + ~GDIPlusStartup() + { + Gdiplus::GdiplusShutdown(token); + } + + } gdistartup; + } + + bool ImageLoader_WinGDI::CreateImageFromFile(olc::Image& image, const std::string& sFileName) + { + // Check file exists + if (!std::filesystem::exists(sFileName)) + return false; // File doesn't exist + + // Load file into windows "bitmap". 1992 calling... + Gdiplus::Bitmap* bmp = nullptr; + bmp = Gdiplus::Bitmap::FromFile(internals::ConvertS2W(sFileName).c_str()); + if (bmp->GetLastStatus() != Gdiplus::Ok) + return false; // File wasn't valid + + // Need to swizzle each pixel... + image.Create(olc::vi2d(bmp->GetWidth(), bmp->GetHeight())); + for (int y = 0; y < image.Size().y; y++) + for (int x = 0; x < image.Size().x; x++) + { + Gdiplus::Color c; + bmp->GetPixel(x, y, &c); + image.Pixel(olc::vi2d(x, y)) = olc::Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha()); + } + + // All done + delete bmp; + return true; + } + + bool ImageLoader_WinGDI::CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes) + { + return false; + } + + bool ImageLoader_WinGDI::CreateImageFromMemory(olc::Image& image, const std::vector& data) + { + return false; + } + + bool ImageLoader_WinGDI::WriteImageToFile(const olc::Image& image, const std::string& sFileName) + { + return false; + } + + bool ImageLoader_WinGDI::WriteImageToMemoryFile(olc::Image& image, const std::vector& data) + { + return false; + } +} +//! END IMPLEMENTATION diff --git a/dev/src/imload_wingdi.h b/dev/src/imload_wingdi.h new file mode 100644 index 00000000..14dae709 --- /dev/null +++ b/dev/src/imload_wingdi.h @@ -0,0 +1,79 @@ +#pragma once + +//! START CUSTOMHEADER +#include "imload_iface.h" +//! END CUSTOMHEADER + +//! START STDHEADER GLOBAL +#include +//! END STDHEADER + +//! START WINAPI_CONFIG +#if defined(UNICODE) || defined(_UNICODE) + #define olcT(s) L##s +#else + #define olcT(s) s +#endif + +#define _WINSOCKAPI_ + +#if !defined(VC_EXTRALEAN) + #define VC_EXTRALEAN +#endif + +#if !defined(NOMINMAX) + #define NOMINMAX +#endif + +// In Code::Blocks +#if !defined(_WIN32_WINNT) + #ifdef HAVE_MSMF + #define _WIN32_WINNT 0x0600 // Windows Vista + #else + #define _WIN32_WINNT 0x0500 // Windows 2000 + #endif +#endif + +// Embrace MSVC superiority +#pragma comment(lib, "gdiplus.lib") +#pragma comment(lib, "Shlwapi.lib") +#include +#include +#include +#include +#undef _WINSOCKAPI_ +//! END WINAPI_CONFIG + +//! START DECLARATION +#if !defined(PGE_IMAGELOADER_WINGDI_DECLARED) +namespace olc +{ + namespace imload + { + class ImageLoader_WinGDI : public ImageLoader + { + public: + + // Create an image resource based on an image file asset on disk + bool CreateImageFromFile(olc::Image& image, const std::string& sFileName) override; + + // Create an image resource based on an image file asset in memory + bool CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes) override; + + // Create an image resource based on an image file asset in memory + bool CreateImageFromMemory(olc::Image& image, const std::vector& data) override; + + // Store an image as a file asset on disk + bool WriteImageToFile(const olc::Image& image, const std::string& sFileName) override; + + // Store an image as a file asset in memory + bool WriteImageToMemoryFile(olc::Image& image, const std::vector& data) override; + + }; + } +} + +#define PGE_IMAGELOADER_WINGDI_DECLARED 1 +#endif +//! END DECLARATION + diff --git a/dev/src/olcpge3.h b/dev/src/olcpge3.h index 90d21e0d..aaf83f12 100644 --- a/dev/src/olcpge3.h +++ b/dev/src/olcpge3.h @@ -7,7 +7,11 @@ #include "transform2d.h" #include "window.h" #include "core.h" + #include "image.h" +#include "imload_iface.h" +#include "imload_wingdi.h" + #include "gputask.h" #include "gpu_iface.h" #include "gpu_opengl33.h" @@ -15,3 +19,4 @@ + diff --git a/dev/src/sh_template.h b/dev/src/sh_template.h index dc0faf12..79e3c5cb 100644 --- a/dev/src/sh_template.h +++ b/dev/src/sh_template.h @@ -20,6 +20,8 @@ //! GRAB transform2d.h DECLARATION //! GRAB image.h DECLARATION + +//! GRAB imload_iface.h DECLARATION //! GRAB gputask.h DECLARATION @@ -27,6 +29,10 @@ //! GRAB draw2d.h DECLARATION +//! GRAB hw_input.h DECLARATION + +//! GRAB hw_mouse.h DECLARATION + //! GRAB window.h DECLARATION //! GRAB host_iface.h DECLARATION @@ -39,6 +45,7 @@ + #if OLC_HOST == OLC_HOST_WINDOWS //! GRAB host_win_winapi.h WINAPI_CONFIG @@ -53,6 +60,12 @@ //! GRAB gpu_opengl33.h DECLARATION #endif +#if OLC_IMAGELOADER == OLC_IMAGELOADER_WINGDI +//! GRAB imload_wingdi.h WINAPI_CONFIG + +//! GRAB imload_wingdi.h DECLARATION +#endif + @@ -91,8 +104,20 @@ #define PGE_IMAGE_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_HW_MOUSE_IMPLEMENTED) +//! GRAB hw_mouse.cpp IMPLEMENTATION +#define PGE_HW_MOUSE_IMPLEMENTED 1 +#endif + #if defined(OLC_PGE_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) //! GRAB window.cpp IMPLEMENTATION #define PGE_WINDOW_IMPLEMENTED 1 #endif +#if defined(OLC_PGE_APPLICATION) && !defined(PGE_IMAGELOADER_IMPLEMENTED) +#if OLC_IMAGELOADER == OLC_IMAGELOADER_WINGDI +//! GRAB imload_wingdi.cpp IMPLEMENTATION +#endif +#define PGE_IMAGELOADER_IMPLEMENTED 1 +#endif + diff --git a/dev/src/window.cpp b/dev/src/window.cpp index 444c993d..5d3e1f2f 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -38,12 +38,13 @@ namespace olc bool Window::olc_OnMouseButton(const uint8_t nButton, const bool bPressed) { + mouse.SetButton(nButton, bPressed); return false; } bool Window::olc_OnMouseMove(const olc::vi2d& vMousePos) - { - volatile_vMousePos = vMousePos; + { + mouse.SetPosition(olc::vf2d(vMousePos) / olc::vf2d(GetSize()) * imgPrimary.Size()); return true; } @@ -76,6 +77,10 @@ namespace olc { // Environmental changes + // Input Changes + mouse.UpdateState(); + + draw.SetGPU(gpu); draw.SetTarget(imgPrimary); @@ -107,9 +112,9 @@ namespace olc // Take the window's completed "screen" and draw it as a textured quad to the backbuffer gpu->AssignTextureTarget(0, 0); gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::TANGERINE, true, true); + gpu->ClearViewport(olc::Colour::BLANK, true, true); draw.ClearTransform(); - draw.Image(imgPrimary, { -1.0,-1.0 }, { 2.0f,2.0f }); + draw.Image(imgPrimary, { -1.0,1.0 }, { 2.0f,-2.0f }); draw.ProcessGPUTasks(); // Update Window's primary surface diff --git a/dev/src/window.h b/dev/src/window.h index 29793f83..d8c88600 100644 --- a/dev/src/window.h +++ b/dev/src/window.h @@ -16,6 +16,7 @@ #include "vector2d.h" #include "gpu_iface.h" #include "draw2d.h" +#include "hw_mouse.h" //! END CUSTOMHEADER //! START DECLARATION @@ -38,9 +39,15 @@ namespace olc class Renderer; } + namespace hw + { + class Mouse; + } + class Window { friend class olc::host::FRIENDLY_HOST; + public: Window(); @@ -109,6 +116,8 @@ namespace olc protected: olc::Draw2D draw; olc::Image imgPrimary; + + olc::hw::Mouse mouse; }; } #define PGE_WINDOW_DECLARED 1 diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index 3316eab3..bccfbb1c 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -11,12 +11,16 @@ class Example : public olc::PixelGameEngine olc::Image imTest; + olc::Image sprite1; + float fAngle = 0.0f; public: bool OnUserCreate() override { - CreateImage(imTest, { 128,128 }); + CreateImage(imTest, { 64,64 }); + CreateImageFromFile(sprite1, "E:/assets/Graphics/Tiles_SideOn/HiQ/FactoryPack/png/256/objects/static/Computer (1).png"); + return true; } @@ -24,52 +28,89 @@ class Example : public olc::PixelGameEngine { fAngle += fElapsedTime; - //draw.AffineRotate(fAngle, { 128,120 }); - //draw.AffineOffset({ 10,10 }); - draw.AffineScale(olc::vf2d(1,1) * (std::sin(fAngle) + 1.1)); - - draw.Rect({ 0,0 }, GetSize() - olc::vf2d{1, 1}, olc::Colour::CYAN); - draw.FillRect({ 100.0f, 30.0f }, { 20.0f, 50.0f }, olc::Colour::TANGERINE); - - - - for (float i = 0; i < 20; i++) - { - draw.AffineRotate(fAngle + (i/50.0f), {128,120}); - if (fmod(i,2) == 1) - { - draw.Line({ 0 + i * 4 ,0 + i * 4 }, { 255 - i * 4, 0 + i * 4 }, olc::Colour::RED, olc::Colour::GREEN); - draw.Line({ 255 - i * 4,0 + i * 4 }, { 255 - i * 4, 239 - i * 4 }, olc::Colour::GREEN, olc::Colour::CYAN); - draw.Line({ 255 - i * 4,239 - i * 4 }, { 0 + i * 4, 239 - i * 4 }, olc::Colour::CYAN, olc::Colour::WHITE); - draw.Line({ 0 + i * 4,239 - i * 4 }, { 0 + i * 4, 0 + i * 4 }, olc::Colour::WHITE, olc::Colour::RED); - } - else - { - draw.Line({ 0 + i * 4 ,0 + i * 4 }, { 255 - i * 4, 0 + i * 4 }, olc::Colour::RED); - draw.Line({ 255 - i * 4,0 + i * 4 }, { 255 - i * 4, 239 - i * 4 }, olc::Colour::GREEN); - draw.Line({ 255 - i * 4,239 - i * 4 }, { 0 + i * 4, 239 - i * 4 }, olc::Colour::CYAN); - draw.Line({ 0 + i * 4,239 - i * 4 }, { 0 + i * 4, 0 + i * 4 }, olc::Colour::WHITE); - } - } - - /*for (int x = 0; x < 100; x++) - { - for (int y = 0; y < 100; y++) - { - if (x % 2 == 0) - { - draw.Pixel(olc::vf2d(x, y) + olc::vf2d(100, 100), olc::Colour::YELLOW); - } - } - }*/ - - //draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); - - draw.FillRect({ 100.0f, 30.0f }, { 20.0f, 50.0f }, olc::Colour::TANGERINE); - - //draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); - //draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); - //draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); + + + + draw.SetTarget(imTest); + draw.FillRect({ 0,0 }, imTest.Size(), olc::Colour::BLUE); + + draw.AffineRotate(fAngle, { 32.0f, 32.0f }); + + draw.Rect({ 5,5 }, { 10,10 }, olc::Colour::YELLOW); + draw.Line({ 0,0 }, { 20, 20 }); + + + draw.SetTarget(imgPrimary); + draw.AffineReset(); + + draw.FillRect({ 0,0 }, imgPrimary.Size(), olc::Colour::VERY_DARK_MAGENTA); + + draw.Line({ 0,0 }, imgPrimary.Size() - 1, olc::Colour::RED); + draw.Line(olc::vf2d( imgPrimary.Size().x - 1, 0 ), olc::vf2d( 0, imgPrimary.Size().y - 1 ), olc::Colour::GREEN); + + if(mouse.GetButton(0).bHeld) + draw.Line({ 0,0 }, mouse.GetPosition(), olc::Colour::TANGERINE); + + draw.AffineRotate(fAngle * 0.2f, imgPrimary.Size() * 0.5f); + draw.Rect({ 0,0 }, imgPrimary.Size()); + draw.Image(imTest, { 10, 10 }, { 64, 64 }); + draw.Image(imTest, { 100, 10 }, { 64, 64 }); + draw.Image(imTest, { 10, 100 }, { 64, 64 }); + draw.Image(sprite1, { 100, 100 }, { 64, 64 }); + + olc::Pixel p = draw.GetPixel(imTest, { 8,5 }); + + draw.FillRect({ 200,200 }, { 10,10 }, p); + + ////draw.AffineRotate(fAngle, { 128,120 }); + ////draw.AffineOffset({ 10,10 }); + //draw.AffineScale(olc::vf2d(1,1) * (std::sin(fAngle) + 1.1)); + + //draw.Rect({ 0,0 }, GetSize() - olc::vf2d{1, 1}, olc::Colour::CYAN); + //draw.FillRect({ 100.0f, 30.0f }, { 20.0f, 50.0f }, olc::Colour::TANGERINE); + + + + //for (float i = 0; i < 20; i++) + //{ + // draw.AffineRotate(fAngle + (i/50.0f), {128,120}); + // if (fmod(i,2) == 1) + // { + // draw.Line({ 0 + i * 4 ,0 + i * 4 }, { 255 - i * 4, 0 + i * 4 }, olc::Colour::RED, olc::Colour::GREEN); + // draw.Line({ 255 - i * 4,0 + i * 4 }, { 255 - i * 4, 239 - i * 4 }, olc::Colour::GREEN, olc::Colour::CYAN); + // draw.Line({ 255 - i * 4,239 - i * 4 }, { 0 + i * 4, 239 - i * 4 }, olc::Colour::CYAN, olc::Colour::WHITE); + // draw.Line({ 0 + i * 4,239 - i * 4 }, { 0 + i * 4, 0 + i * 4 }, olc::Colour::WHITE, olc::Colour::RED); + // } + // else + // { + // draw.Line({ 0 + i * 4 ,0 + i * 4 }, { 255 - i * 4, 0 + i * 4 }, olc::Colour::RED); + // draw.Line({ 255 - i * 4,0 + i * 4 }, { 255 - i * 4, 239 - i * 4 }, olc::Colour::GREEN); + // draw.Line({ 255 - i * 4,239 - i * 4 }, { 0 + i * 4, 239 - i * 4 }, olc::Colour::CYAN); + // draw.Line({ 0 + i * 4,239 - i * 4 }, { 0 + i * 4, 0 + i * 4 }, olc::Colour::WHITE); + // } + //} + + ///*for (int x = 0; x < 100; x++) + //{ + // for (int y = 0; y < 100; y++) + // { + // if (x % 2 == 0) + // { + // draw.Pixel(olc::vf2d(x, y) + olc::vf2d(100, 100), olc::Colour::YELLOW); + // } + // } + //}*/ + + ////draw.Pixel({ -0.5f, -0.25f }, olc::Colour::YELLOW); + + //draw.FillRect({ 100.0f, 30.0f }, { 20.0f, 50.0f }, olc::Colour::TANGERINE); + + ////draw.Pixel({ 0.3f, 0.3f }, olc::Colour::BLACK); + ////draw.Pixel({ 0.32f, 0.3f }, olc::Colour::BLACK); + ////draw.Pixel({ 0.34f, 0.3f }, olc::Colour::BLACK); + + + return true; } @@ -79,6 +120,7 @@ int main() { Example demo; if (demo.Construct({ 256, 240 }, { 4, 4 })) + //if (demo.Construct({ 1280, 960 }, { 1, 1 })) demo.Start(); return 0; From 4f6ac43d4abd4db2ce97f2ddad1ec35af3dfe023 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Sun, 14 Sep 2025 22:41:52 +0100 Subject: [PATCH 08/11] introduced sub-image regions --- dev/src/draw2d.cpp | 11 ++++++----- dev/src/draw2d.h | 41 +++++++++++++++++++++++++++++++++++++++-- dev/src/image.cpp | 11 +++++++++++ dev/src/image.h | 20 ++++++++++++++++++++ dev/tests/test_mh.cpp | 10 ++++++---- 5 files changed, 82 insertions(+), 11 deletions(-) diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index 905f3435..6ef6eab6 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -243,7 +243,7 @@ GPUTask olc::Draw2D::Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc } -GPUTask olc::Draw2D::FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) +GPUTask olc::Draw2D::FilledRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) { PrepareTargetForHW(); return vecGPUTasks.emplace_back( @@ -255,10 +255,10 @@ GPUTask olc::Draw2D::FillRect(const olc::vf2d& pos, const olc::vf2d& size, const )); } -GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size) +GPUTask olc::Draw2D::Image(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& size) { // Ensure source image is up to date in VRAM - PrepareImageForHW(image); + PrepareImageForHW(image.image); PrepareTargetForHW(); return vecGPUTasks.emplace_back( @@ -266,8 +266,9 @@ GPUTask olc::Draw2D::Image(olc::Image& image, const olc::vf2d& pos, const olc::v GPUTask::Structure::Fan, transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, - { {0,0}, {1,0}, {1,1}, {0,1} }, - &image + // Tex coords are clockwise + { image.coords[0], image.coords[1], image.coords[3], image.coords[2]}, + &image.image )); } diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index d57602d2..40943b4d 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -79,6 +79,8 @@ namespace olc void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); // Read a pixel from an image (guarantees fresh) olc::Pixel GetPixel(olc::Image& image, const olc::vf2d& pos); + + // Clear public: // Draws a single pixel wide line @@ -89,10 +91,45 @@ namespace olc // Draws a rectangle outline GPUTask Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); // Draws a filled, single colour rectangle - GPUTask FillRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + GPUTask FilledRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + + //GPUTask ShadedRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colTR, const olc::Pixel colBL, const olc::Pixel colBR); + //TexturedRect + + + //Circle + //FilledCircle + //ShadedCircle + //TexturedCircle + + //Ellipse + //FilledEllipse + //ShadedEllipse + //TexturedEllipse + + //RoundRect + //FilledRoundRect + //ShadedRoundRect + //TexturedRoundRect + + //Triangle + //FilledTriangle + //ShadedTriangle + //TexturedTriangle + + //Polygon + //FilledPolygon + //ShadedPolygon + //TexturedPolygon + // Draws an image - GPUTask Image(olc::Image& image, const olc::vf2d& pos, const olc::vf2d& size); + GPUTask Image(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& scale = { 1.0f, 1.0f }); + + + + // ImageRotated + // ImageWarped diff --git a/dev/src/image.cpp b/dev/src/image.cpp index 2c528b96..46ad8a12 100644 --- a/dev/src/image.cpp +++ b/dev/src/image.cpp @@ -64,6 +64,17 @@ namespace olc return onCPU; } + olc::ImageRegion Image::region(const olc::vf2d pos, const olc::vf2d& size) + { + return region(pos, { pos.x + size.x, pos.y }, { pos.x, pos.y + size.y }, pos + size); + } + + olc::ImageRegion Image::region(const olc::vf2d& vTL, const olc::vf2d& vTR, const olc::vf2d& vBL, const olc::vf2d& vBR) + { + auto i = 1.0f / this->Size(); + return olc::ImageRegion(*this, vTL * i, vTR * i, vBL * i, vBR * i ); + } + void Image::BindGPU() { onGPU = true; diff --git a/dev/src/image.h b/dev/src/image.h index 72bf441f..e8842d69 100644 --- a/dev/src/image.h +++ b/dev/src/image.h @@ -27,6 +27,8 @@ namespace olc bool InVRAM = true; }; + struct ImageRegion; + class Image { public: @@ -56,6 +58,10 @@ namespace olc bool BoundToGPU() const; bool BoundToCPU() const; + olc::ImageRegion region(const olc::vf2d pos, const olc::vf2d& size); + olc::ImageRegion region(const olc::vf2d& vTL, const olc::vf2d& vTR, const olc::vf2d& vBL, const olc::vf2d& vBR); + + public: // Make friendly private later void BindGPU(); void BindCPU(); @@ -68,6 +74,20 @@ namespace olc bool onGPU = false; bool onCPU = true; }; + + struct ImageRegion + { + ImageRegion(olc::Image& i, const olc::vf2d& vTL = { 0,0 }, const olc::vf2d& vTR = { 1,0 }, const olc::vf2d& vBL = { 0,1 }, const olc::vf2d& vBR = { 1,1 }) + : image(i) + { + coords = { vTL, vTR, vBL, vBR }; + } + + olc::Image& image; + std::array coords; + }; + + } #define PGE_IMAGE_DECLARED 1 #endif diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index bccfbb1c..7b22c73d 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -32,7 +32,7 @@ class Example : public olc::PixelGameEngine draw.SetTarget(imTest); - draw.FillRect({ 0,0 }, imTest.Size(), olc::Colour::BLUE); + draw.FilledRect({ 0,0 }, imTest.Size(), olc::Colour::BLUE); draw.AffineRotate(fAngle, { 32.0f, 32.0f }); @@ -43,7 +43,7 @@ class Example : public olc::PixelGameEngine draw.SetTarget(imgPrimary); draw.AffineReset(); - draw.FillRect({ 0,0 }, imgPrimary.Size(), olc::Colour::VERY_DARK_MAGENTA); + draw.FilledRect({ 0,0 }, imgPrimary.Size(), olc::Colour::VERY_DARK_MAGENTA); draw.Line({ 0,0 }, imgPrimary.Size() - 1, olc::Colour::RED); draw.Line(olc::vf2d( imgPrimary.Size().x - 1, 0 ), olc::vf2d( 0, imgPrimary.Size().y - 1 ), olc::Colour::GREEN); @@ -56,11 +56,13 @@ class Example : public olc::PixelGameEngine draw.Image(imTest, { 10, 10 }, { 64, 64 }); draw.Image(imTest, { 100, 10 }, { 64, 64 }); draw.Image(imTest, { 10, 100 }, { 64, 64 }); + draw.Image(sprite1, { 100, 100 }, { 64, 64 }); - + draw.Image(sprite1.region({ 20.0f, 20.0f }, { 32.0f, 32.0f }), { 200, 100 }, { 32, 32 }); + draw.Image(sprite1.region({ 20.0f, 20.0f }, { 32.0f, 32.0f }, { 100.0f, 200.0f }, { 150.0f, 180.0f }), { 100, 200 }, { 32, 32 }); olc::Pixel p = draw.GetPixel(imTest, { 8,5 }); - draw.FillRect({ 200,200 }, { 10,10 }, p); + draw.FilledRect({ 200,200 }, { 10,10 }, p); ////draw.AffineRotate(fAngle, { 128,120 }); ////draw.AffineOffset({ 10,10 }); From d43c2b518270010162abf76b1ca74db21bf35d41 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Thu, 18 Sep 2025 21:49:28 +0100 Subject: [PATCH 09/11] Added warping and various image draw calls --- dev/src/draw2d.cpp | 137 +++++++++++++++++++++++++++++++++++++-- dev/src/draw2d.h | 123 +++++++++++++++++++++++++---------- dev/src/gpu_opengl33.cpp | 6 +- dev/src/gputask.h | 1 + dev/src/image.h | 15 ++++- dev/src/matrix3d.h | 11 ++++ dev/src/transform2d.h | 8 +-- dev/src/window.cpp | 2 +- dev/tests/olc.png | Bin 0 -> 2417 bytes dev/tests/test_mh.cpp | 114 +++++++++++++++++++++++++++++--- 10 files changed, 358 insertions(+), 59 deletions(-) create mode 100644 dev/tests/olc.png diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index 6ef6eab6..47034824 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -30,7 +30,7 @@ void Draw2D::SetTarget(olc::Image& image) -1.0f + (1.0f / float(pTarget->Size().y)) )); - AffineReset(); + WorldReset(); pRenderer->AssignTextureTarget(0, pTarget->GetGPUID()); pRenderer->SetViewport({ 0,0 }, pTarget->Size()); @@ -115,30 +115,40 @@ void Draw2D::PrepareImageForHW(olc::Image& image) } } -void olc::Draw2D::AffineReset() +void olc::Draw2D::WorldReset() { transformAffine = olc::tf2d(); transformCombined = transformAffine * transformTarget; } -void olc::Draw2D::AffineScale(const olc::vf2d& vScale) +void olc::Draw2D::WorldScale(const olc::vf2d& vScale) { transformAffine.scale(vScale); transformCombined = transformAffine * transformTarget; } -void olc::Draw2D::AffineOffset(const olc::vf2d& vOffset) +void olc::Draw2D::WorldOffset(const olc::vf2d& vOffset) { transformAffine.translate(vOffset); transformCombined = transformAffine * transformTarget; } -void olc::Draw2D::AffineRotate(const float& fTheta, const olc::vf2d& vPoint) +void olc::Draw2D::WorldRotate(const float& fTheta, const olc::vf2d& vPoint) { transformAffine.rotate(fTheta, vPoint); transformCombined = transformAffine * transformTarget; } +olc::vf2d olc::Draw2D::WorldToScreen(const olc::vf2d& v) const +{ + return transformAffine.forward(v); +} + +olc::vf2d olc::Draw2D::ScreenToWorld(const olc::vf2d& v) const +{ + return transformAffine.inverse(v); +} + void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { // Check if in bounds @@ -203,6 +213,17 @@ GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std task.vertexBuffer.push_back({ vPoints[i].x, vPoints[i].y, 1.0f, 1.0f, vColours[i], vTexCoords[i].x, vTexCoords[i].y, 0, 0, 0, 0, 0, 0}); task.pImage = image; task.tint = tint; + //task.mvpMatrix = transformCombined.m4x4(); + return task; +} + +GPUTask olc::Draw2D::TaskTexturedPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vZWs, const std::vector& vColours, const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint) +{ + GPUTask task; + for (size_t i = 0; i < vPoints.size(); i++) + task.vertexBuffer.push_back({ vPoints[i].x, vPoints[i].y, vZWs[i].x, vZWs[i].y, vColours[i], vTexCoords[i].x, vTexCoords[i].y, 0, 0, 0, 0, 0, 0}); + task.pImage = image; + task.tint = tint; return task; } @@ -255,22 +276,124 @@ GPUTask olc::Draw2D::FilledRect(const olc::vf2d& pos, const olc::vf2d& size, con )); } -GPUTask olc::Draw2D::Image(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& size) +GPUTask olc::Draw2D::Image(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& scale) { // Ensure source image is up to date in VRAM PrepareImageForHW(image.image); PrepareTargetForHW(); + + olc::vf2d size = image.regionsize * scale; + return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + //{ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, // Tex coords are clockwise - { image.coords[0], image.coords[1], image.coords[3], image.coords[2]}, + { image.coords[0], image.coords[1], image.coords[2], image.coords[3]}, + &image.image + )); +} + +GPUTask olc::Draw2D::ImageRotated(olc::ImageRegion image, const olc::vf2d& pos, const float theta, const olc::vf2d& center, const olc::vf2d& scale) +{ + // Ensure source image is up to date in VRAM + PrepareImageForHW(image.image); + PrepareTargetForHW(); + + olc::vf2d size = image.regionsize * scale; + + std::vector vPoints(4); + vPoints[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale; + vPoints[1] = (olc::vf2d(size.x, 0.0f) - center) * scale; + vPoints[2] = (size - center) * scale; + vPoints[3] = (olc::vf2d(0.0f, size.y) - center) * scale; + + float c = cos(theta), s = sin(theta); + for (int i = 0; i < 4; i++) + vPoints[i] = pos + olc::vf2d(vPoints[i].x * c - vPoints[i].y * s, vPoints[i].x * s + vPoints[i].y * c); + + return vecGPUTasks.emplace_back( + TaskTexturedPolygon( + GPUTask::Structure::Fan, + transformCombined.transform(vPoints), + { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, + { image.coords[0], image.coords[1], image.coords[2], image.coords[3] }, &image.image )); } +GPUTask olc::Draw2D::ImageQuad(olc::ImageRegion image, const olc::vf2d& vTL, const olc::vf2d& vTR, const olc::vf2d& vBR, const olc::vf2d& vBL) +{ + // Ensure source image is up to date in VRAM + PrepareImageForHW(image.image); + PrepareTargetForHW(); + + + float rd = ((vBR.x - vTL.x) * (vTR.y - vBL.y) - (vTR.x - vBL.x) * (vBR.y - vTL.y)); + if (rd != 0) + { + rd = 1.0f / rd; + float rn = ((vTR.x - vBL.x) * (vTL.y - vBL.y) - (vTR.y - vBL.y) * (vTL.x - vBL.x)) * rd; + float sn = ((vBR.x - vTL.x) * (vTL.y - vBL.y) - (vBR.y - vTL.y) * (vTL.x - vBL.x)) * rd; + + olc::vf2d center; + if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) + center = vTL + rn * (vBR - vTL); + + std::array d = { { + (vTL - center).mag(), + (vTR - center).mag(), + (vBR - center).mag(), + (vBL - center).mag(), + } }; + + std::array q = { { + d[0] == 0.0f ? 1.0f : (d[0] + d[2]) / d[2], + d[1] == 0.0f ? 1.0f : (d[1] + d[3]) / d[3], + d[2] == 0.0f ? 1.0f : (d[2] + d[0]) / d[0], + d[3] == 0.0f ? 1.0f : (d[3] + d[1]) / d[1], + } }; + + return vecGPUTasks.emplace_back( + TaskTexturedPolygon( + GPUTask::Structure::Fan, + transformCombined.transform({ vTL, vTR, vBR, vBL }), + { {q[0], 1.0f}, {q[1], 1.0f}, {q[2], 1.0f}, {q[3], 1.0f} }, + { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, + { image.coords[0] * q[0], image.coords[1] * q[1], image.coords[2] * q[2], image.coords[3] * q[3] }, + &image.image + )); + } + + return GPUTask(); +} + +GPUTask olc::Draw2D::ImageQuad(olc::ImageRegion image, const std::vector& vecPoints) +{ + return ImageQuad(image, vecPoints[0], vecPoints[1], vecPoints[2], vecPoints[3]); +} + + +GPUTask olc::Draw2D::ImageRect(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& size) +{ + // Ensure source image is up to date in VRAM + PrepareImageForHW(image.image); + + PrepareTargetForHW(); + + return vecGPUTasks.emplace_back( + TaskTexturedPolygon( + GPUTask::Structure::Fan, + transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + //{ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, + { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, + // Tex coords are clockwise + { image.coords[0], image.coords[1], image.coords[2], image.coords[3] }, + &image.image + )); +} //! END IMPLEMENTATION \ No newline at end of file diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index 40943b4d..9e453106 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -49,49 +49,54 @@ namespace olc void ProcessGPUTasks(); - protected: - // Checks residency of image resource, and brings it to cpu RAM for r/w - void PrepareTargetForSW(); - // Checks residency of image resource, and brings it to gpu VRAM for r/w - void PrepareTargetForHW(); - - // Checks residency of image resource, and brings it to cpu RAM for r/w - void PrepareImageForSW(olc::Image& image); - // Checks residency of image resource, and brings it to gpu VRAM for r/w - void PrepareImageForHW(olc::Image& image); - - olc::Image* pTarget = nullptr; - olc::gpu::Renderer* pRenderer = nullptr; - olc::tf2d transformTarget; - olc::tf2d transformAffine; - olc::mf3d transformCombined; - - std::vector vecGPUTasks; + public: // Affine Transformation (these affect all subsequent draw calls for this target) - void AffineReset(); - void AffineScale(const olc::vf2d& vScale); - void AffineOffset(const olc::vf2d& vOffset); - void AffineRotate(const float& fTheta, const olc::vf2d& vPoint = { 0,0 }); + void WorldReset(); + void WorldScale(const olc::vf2d& vScale); + void WorldOffset(const olc::vf2d& vOffset); + void WorldRotate(const float& fTheta, const olc::vf2d& vPoint = { 0,0 }); + olc::vf2d WorldToScreen(const olc::vf2d& v) const; + olc::vf2d ScreenToWorld(const olc::vf2d& v) const; public: // Plot a single pixel - void Pixel(const olc::vf2d& pos, const olc::Pixel col = olc::Colour::WHITE); + void Pixel( + const olc::vf2d& pos, + const olc::Pixel col = olc::Colour::WHITE); + // Read a pixel from an image (guarantees fresh) - olc::Pixel GetPixel(olc::Image& image, const olc::vf2d& pos); + olc::Pixel GetPixel( + olc::Image& image, + const olc::vf2d& pos); // Clear public: // Draws a single pixel wide line - GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::Colour::WHITE); + GPUTask Line( + const olc::vf2d& p1, + const olc::vf2d& p2, + const olc::Pixel col = olc::Colour::WHITE); + // Draws a single pixel wide line with a gradient - GPUTask Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c1, const olc::Pixel c2); + GPUTask Line( + const olc::vf2d& p1, + const olc::vf2d& p2, + const olc::Pixel c1, + const olc::Pixel c2); // Draws a rectangle outline - GPUTask Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + GPUTask Rect( + const olc::vf2d& pos, + const olc::vf2d& size, + const olc::Pixel col = olc::Colour::WHITE); + // Draws a filled, single colour rectangle - GPUTask FilledRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::Colour::WHITE); + GPUTask FilledRect( + const olc::vf2d& pos, + const olc::vf2d& size, + const olc::Pixel col = olc::Colour::WHITE); //GPUTask ShadedRect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colTR, const olc::Pixel colBL, const olc::Pixel colBR); //TexturedRect @@ -123,13 +128,35 @@ namespace olc //TexturedPolygon - // Draws an image - GPUTask Image(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& scale = { 1.0f, 1.0f }); - - + // Draws a scaled image at specified location + GPUTask Image( + olc::ImageRegion image, + const olc::vf2d& pos, + const olc::vf2d& scale = { 1.0f, 1.0f }); - // ImageRotated - // ImageWarped + // Draws an image rotated around a point at specified location + GPUTask ImageRotated( + olc::ImageRegion image, + const olc::vf2d& pos, + const float theta, + const olc::vf2d& center = { 0.0f, 0.0f }, + const olc::vf2d& scale = { 1.0f, 1.0f }); + + // Draws an image warped correctly to linearly fill a quadrilateral (formerly DrawWarped...) + GPUTask ImageQuad( + olc::ImageRegion image, + const olc::vf2d& vTL, + const olc::vf2d& vTR, + const olc::vf2d& vBR, + const olc::vf2d& vBL); + + GPUTask ImageQuad( + olc::ImageRegion image, + const std::vector& vecPoints); + + + // Draws an image scaled to a specified rectangular area + GPUTask ImageRect(olc::ImageRegion image, const olc::vf2d& pos, const olc::vf2d& size); @@ -166,6 +193,34 @@ namespace olc const std::vector& vTexCoords, olc::Image* const image, const olc::Pixel tint = olc::Colour::WHITE); + + GPUTask TaskTexturedPolygon( + GPUTask::Structure structure, + const std::vector& vPoints, + const std::vector& vZWs, + const std::vector& vColours, + const std::vector& vTexCoords, + olc::Image* const image, + const olc::Pixel tint = olc::Colour::WHITE); + + protected: + // Checks residency of image resource, and brings it to cpu RAM for r/w + void PrepareTargetForSW(); + // Checks residency of image resource, and brings it to gpu VRAM for r/w + void PrepareTargetForHW(); + + // Checks residency of image resource, and brings it to cpu RAM for r/w + void PrepareImageForSW(olc::Image& image); + // Checks residency of image resource, and brings it to gpu VRAM for r/w + void PrepareImageForHW(olc::Image& image); + + olc::Image* pTarget = nullptr; + olc::gpu::Renderer* pRenderer = nullptr; + olc::tf2d transformTarget; + olc::tf2d transformAffine; + olc::mf3d transformCombined; + + std::vector vecGPUTasks; }; } diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index 698247de..50298b10 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -139,6 +139,8 @@ namespace olc::gpu "out vec2 oTex;\n" "out vec4 oCol;\n" "void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex;} oCol = aCol * tint;}" + //"void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = mvp * (p * vec4(aPos.x, aPos.y, 0.0, 1.0)); oTex = p * aTex;} oCol = aCol * tint;}" + ); shaderDefault.Compile(); @@ -332,6 +334,8 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); gl.glUseProgram(shaderDefault.GetShaderID()); + + return true; } @@ -361,7 +365,7 @@ namespace olc::gpu gl.glUniform1i(shaderDefault.GetUniform("is3d"), 0); // Shader: Apply MVP Matrix - gl.glUniformMatrix4fv(shaderDefault.GetUniform("mvp"), 1, false, task.mvpMatrix.data()); + //gl.glUniformMatrix4fv(shaderDefault.GetUniform("mvp"), 1, true, task.mvpMatrix.data()); // Shader: Apply Global Tint float f[4] = { diff --git a/dev/src/gputask.h b/dev/src/gputask.h index 768d03c8..9c86491b 100644 --- a/dev/src/gputask.h +++ b/dev/src/gputask.h @@ -30,6 +30,7 @@ namespace olc enum class Task : uint8_t { DrawPolygon, + NullTask } task = Task::DrawPolygon; struct Vertex diff --git a/dev/src/image.h b/dev/src/image.h index e8842d69..d8b9300e 100644 --- a/dev/src/image.h +++ b/dev/src/image.h @@ -80,11 +80,20 @@ namespace olc ImageRegion(olc::Image& i, const olc::vf2d& vTL = { 0,0 }, const olc::vf2d& vTR = { 1,0 }, const olc::vf2d& vBL = { 0,1 }, const olc::vf2d& vBR = { 1,1 }) : image(i) { - coords = { vTL, vTR, vBL, vBR }; + coords = { vTL, vTR, vBR, vBL }; + regionsize = (vBR - vTL) * image.Size(); } - olc::Image& image; - std::array coords; + olc::Image& image; + olc::vf2d regionsize; + union + { + std::array coords; + olc::vf2d tl; + olc::vf2d tr; + olc::vf2d br; + olc::vf2d bl; + }; }; diff --git a/dev/src/matrix3d.h b/dev/src/matrix3d.h index fa5c2dd5..1d90418b 100644 --- a/dev/src/matrix3d.h +++ b/dev/src/matrix3d.h @@ -81,6 +81,17 @@ namespace olc me(2, 2) = 1; } + inline constexpr std::array m4x4() + { + auto& me = (*this); + return { + me(0,0), me(1,0), me(2,0), 0, + me(0,1), me(1,1), me(2,1), 0, + me(0,2), me(1,2), me(2,2), 0, + 0, 0, 0, 1 + }; + } + // Create translation matrix via components template inline constexpr void translate(const Q x, const Q y) diff --git a/dev/src/transform2d.h b/dev/src/transform2d.h index cfe7b561..0fcd5777 100644 --- a/dev/src/transform2d.h +++ b/dev/src/transform2d.h @@ -50,14 +50,14 @@ namespace olc // Transform a vector by this transform template - inline constexpr auto forward(const olc::v_2d& v) + inline constexpr auto forward(const olc::v_2d& v) const { return m_mForward * v; } // Transform a vector of v_2d by this transform template - inline constexpr auto forward(const std::vector>& v) + inline constexpr auto forward(const std::vector>& v) const { std::vector> o(v.size()); std::transform(v.begin(), v.end(), o.begin(), [this](const olc::v_2d& i) {return m_mForward * i; }); @@ -66,14 +66,14 @@ namespace olc // Transform a vector by the inverse of this transform template - inline constexpr auto inverse(const olc::v_2d& v) + inline constexpr auto inverse(const olc::v_2d& v) const { return m_mInverse * v; } // Transform a vector by this transform template - inline constexpr auto inverse(const std::vector>& v) + inline constexpr auto inverse(const std::vector>& v) const { std::vector> o(v.size()); std::transform(v.begin(), v.end(), o.begin(), [this](const olc::v_2d& i) {return m_mInverse * i; }); diff --git a/dev/src/window.cpp b/dev/src/window.cpp index 5d3e1f2f..b1b7c3bc 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -114,7 +114,7 @@ namespace olc gpu->SetViewport({ 0,0 }, GetSize()); gpu->ClearViewport(olc::Colour::BLANK, true, true); draw.ClearTransform(); - draw.Image(imgPrimary, { -1.0,1.0 }, { 2.0f,-2.0f }); + draw.ImageRect(imgPrimary, { -1.0,1.0 }, { 2.0f,-2.0f }); draw.ProcessGPUTasks(); // Update Window's primary surface diff --git a/dev/tests/olc.png b/dev/tests/olc.png new file mode 100644 index 0000000000000000000000000000000000000000..fb4a6a3952b86d15f4d3b6e14a4942f961abe680 GIT binary patch literal 2417 zcmai0eN-$%p12yW9Kzp7-}W@9+7z zdqb0v8t6aCA3=~nRhl9Te)HgGik~lhh6k+MfFQmL$((#9U!5-2Qf3~Zqly5}X|_Tf zK_n?oE1@j`3|a&Xq(zGTee??qC3R9PFJ8@8Tjjt=rj^qmyF4RDTVA3S>9CY!e~D8J z3Cw^YP^Z~sv5B2h%*`u?zu9dZL)|7!i4@CMYfw2w12mo&&*Njs{-}i3>BU)!x&4RX zN{Sg7#wx~fhr_{h#PTTGfD1$-5zZIlLLnDgaBXE4hH!E%wg{HO!=V5+ElpY(lCq#I zCs9P%87YQA9PKC9X}#Q5J8g0^>$Es90W+{LHeA3H-~;V}lYA15#nvwu6b@$*XwDyG zZZ%R2WiwJ%ua`k*yzsDt45@#H9~K#A4&{Ej2Pa{Dnz35_|K?`%pljF|WhoS{KM8}b z@YsPZr_2iQEMTMTv=%5!p?VQ+;aFY7a>_)}*|3y=6caqz){stM%2$w3Ya2|G6pKq3 z0u~Gag-LGEE1HK@P3a(M><~ynFhEWN_=L48{@uG^Hm^kkFQuItNuL?Q_FUXU&?Os5P~p@yOvnjo1%cQIsZ2@{auY`2=oepdJDF|7n2Z8I zvH@XagQbJRa5p{M_N+ajWwRm0tTd&wYk|(45cg1EQ5&Ua90Uzy23W;XOs3b9FmGk3 zhV5olhzjAP@)Vr+h{FgV-LOK7jqNWq{HejX`|6p&c+h7B1BV-FumE~!Jf2hDc%G5$ z{&+k}Kh{cu4^z`)Fkq0vdwBNXfQFME_l|nF@V+d71$G?`Uj>W)T;72oJ}XJsS;IOC zL1t{QZ#XhvE(@wk2|2ONZ-0}fn$yVn-cL5UraG)n$?2$9z08~1d8K{i=$2KDJJFw< zq4&d#(fI+ZYW<2D8*A6Cxz-jL6dZf{=Bp1bzE3#D$8_v|=WNL+bkn!R4^=y~#L}-a zAI*zMxXGLg&0_2c{NUXmFTa$nJ-PUBLH+$B6^$ZJcW50M6rP*Ijh0N4G;hvTUkbM5 zaduVTay89=H^9HgRo;3WpWZpY&wOC~zi(B3q`naR=)~p1hRA~(o7$!rX1cP!z9T3+ z%Ta$fD)M%;RN8#qz2@muOd z`@%O(2$9Z=P+hwDsOR(R`=>70S6(yj`Uinm+QY6N-qi#q6sE4pO!B=EvSd&6J(qmK z!=UB$wW4vyT70hMg>u^h!nSq&Q@7@zCiB4B#YF<=tkpj#n|fxSqxTv9Se_A%w(<(? zfy*9rMO`yTr&M+udXxJq=E7I{Xlq)54M74z*pCmgb^8REpm>!+mXp7_J5R>>lJB=< z`+BNZmVA2Dz3I49bAC^daZ=IISZQ43#;(}I&x1;r?k1A2yWGUcsmS9xv{l(3|G{dhn*voR^+LROTz zvLvqS?U%9^{<voK4oeeWHUV7j`Jmr+4;_VzA{sYMsHVps( literal 0 HcmV?d00001 diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index 7b22c73d..be67b500 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -11,27 +11,123 @@ class Example : public olc::PixelGameEngine olc::Image imTest; - olc::Image sprite1; + olc::Image imLogo; float fAngle = 0.0f; + + struct logo + { + olc::vf2d pos; + olc::vf2d vel; + float ang; + float angvel; + }; + std::vector vecLogos; + + std::vector vecVerts; + + + int nSelectedVert = -1; + public: bool OnUserCreate() override { - CreateImage(imTest, { 64,64 }); - CreateImageFromFile(sprite1, "E:/assets/Graphics/Tiles_SideOn/HiQ/FactoryPack/png/256/objects/static/Computer (1).png"); + //CreateImage(imTest, { 64,64 }); + CreateImageFromFile(imLogo, "../tests/olc.png"); + + + size_t x = 1; + vecLogos.resize(x); + for (auto& a : vecLogos) + { + a.pos = olc::vf2d(rand() % imgPrimary.Size().x, rand() % imgPrimary.Size().y); + //a.vel = olc::vf2d(rand() % 100 - 50, rand() % 100 - 50); + a.angvel = 1.1f; + } + + vecVerts = { + {200.0f, 200.0f}, + { 400.0f, 200.0f}, + { 400.0f, 400.0f}, + {200.0f, 400.0f} + }; return true; } bool OnUserUpdate(float fElapsedTime) override { - fAngle += fElapsedTime; - + fAngle += 0.1f * fElapsedTime; + draw.WorldRotate(fAngle, imgPrimary.Size() / 2.0f); + auto vMouse = draw.ScreenToWorld(mouse.GetPosition()); + + if (mouse.GetButton(0).bPressed) + { + float dist = 100000.0f; + int idx = -1; + for (int i = 0; i < 4; i++) + { + float d = (vecVerts[i] - vMouse).mag(); + if (d < 8 && d < dist) + { + dist = d; + idx = i; + } + } + nSelectedVert = idx; + } + + if (nSelectedVert != -1 && mouse.GetButton(0).bHeld) + vecVerts[nSelectedVert] = vMouse; + + if (mouse.GetButton(0).bReleased) + nSelectedVert = -1; + + draw.ImageQuad(imLogo.region({ 0,0 }, { 10,10 }), vecVerts); + + draw.Line(vecVerts[0], vecVerts[1], olc::Colour::MAGENTA); + draw.Line(vecVerts[1], vecVerts[2], olc::Colour::MAGENTA); + draw.Line(vecVerts[2], vecVerts[3], olc::Colour::MAGENTA); + draw.Line(vecVerts[3], vecVerts[0], olc::Colour::MAGENTA); + + + + /*for (auto& a : vecLogos) + { + a.pos += a.vel * fElapsedTime; + a.ang += a.angvel * fElapsedTime; + + if (a.pos.x >= imgPrimary.Size().x - 46) + { + a.pos.x = imgPrimary.Size().x - 46; + a.vel.x *= -1.0f; + } + + if (a.pos.y >= imgPrimary.Size().y - 28) + { + a.pos.y = imgPrimary.Size().y - 28; + a.vel.y *= -1.0f; + } + + if (a.pos.x < 0) + { + a.pos.x = 0; + a.vel.x *= -1.0f; + } + + if (a.pos.y < 0) + { + a.pos.y = 0; + a.vel.y *= -1.0f; + } + + draw.ImageRotated(imLogo, a.pos, a.ang, { 10,10 }, { 2.0f, 4.0f }); + }*/ - draw.SetTarget(imTest); + /*draw.SetTarget(imTest); draw.FilledRect({ 0,0 }, imTest.Size(), olc::Colour::BLUE); draw.AffineRotate(fAngle, { 32.0f, 32.0f }); @@ -62,7 +158,7 @@ class Example : public olc::PixelGameEngine draw.Image(sprite1.region({ 20.0f, 20.0f }, { 32.0f, 32.0f }, { 100.0f, 200.0f }, { 150.0f, 180.0f }), { 100, 200 }, { 32, 32 }); olc::Pixel p = draw.GetPixel(imTest, { 8,5 }); - draw.FilledRect({ 200,200 }, { 10,10 }, p); + draw.FilledRect({ 200,200 }, { 10,10 }, p);*/ ////draw.AffineRotate(fAngle, { 128,120 }); ////draw.AffineOffset({ 10,10 }); @@ -121,8 +217,8 @@ class Example : public olc::PixelGameEngine int main() { Example demo; - if (demo.Construct({ 256, 240 }, { 4, 4 })) - //if (demo.Construct({ 1280, 960 }, { 1, 1 })) + //if (demo.Construct({ 256, 240 }, { 4, 4 })) + if (demo.Construct({ 1280, 960 }, { 1, 1 })) demo.Start(); return 0; From 3473085f5c0bd9debf0fea0d73f8b331471f14e4 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Thu, 25 Sep 2025 22:02:13 +0100 Subject: [PATCH 10/11] The DAMN YOU TGD update --- dev/src/core.cpp | 14 ++++-- dev/src/draw2d.cpp | 67 +++++++++++++++++++++++------ dev/src/draw2d.h | 1 + dev/src/gpu_opengl33.cpp | 92 ++++++++++++++++++++++++++++----------- dev/src/gpu_opengl33.h | 1 + dev/src/image.cpp | 2 +- dev/src/window.cpp | 7 +-- dev/tests/test_mh.cpp | 93 +++++++++++++++++++++++++++++++++++++--- 8 files changed, 226 insertions(+), 51 deletions(-) diff --git a/dev/src/core.cpp b/dev/src/core.cpp index 2a5e204c..33781124 100644 --- a/dev/src/core.cpp +++ b/dev/src/core.cpp @@ -27,8 +27,7 @@ namespace olc bool PixelGameEngine::Construct(const PGEConfig& cfg) { config = cfg; - - return false; + return true; } bool PixelGameEngine::Start() @@ -156,6 +155,8 @@ namespace olc // Initialise GPU Interface - This thread is the context olc::gpu::RendererConfig cfgRenderer; + cfgRenderer.VerticalSync = config.bVSync; + gpu = std::make_unique(); // The GPU device can be based upon the primary window configuration. This @@ -171,7 +172,11 @@ namespace olc CreateImage(imgPrimary, config.vScreenSize); - gpu->WriteTexture(imgPrimary.GetGPUID(), imgPrimary); + + + draw.SetGPU(gpu.get()); + gpu->ApplyDefaultShader(); + draw.SetTarget(imgPrimary); if (!OnUserCreate()) { @@ -179,7 +184,8 @@ namespace olc return; } - + draw.ProcessGPUTasks(); + draw.SetTarget(imgPrimary); // Initialise Input Devices diff --git a/dev/src/draw2d.cpp b/dev/src/draw2d.cpp index 47034824..d639ab34 100644 --- a/dev/src/draw2d.cpp +++ b/dev/src/draw2d.cpp @@ -16,8 +16,12 @@ void Draw2D::SetGPU(olc::gpu::Renderer* const renderer) void Draw2D::SetTarget(olc::Image& image) { + // Perform any outstanding tasks for current target ProcessGPUTasks(); + // Endure new target exists in GPU up to date + PrepareImageForHW(image); + // Store the target image pTarget = ℑ @@ -26,8 +30,8 @@ void Draw2D::SetTarget(olc::Image& image) transformTarget.scale(olc::vf2d(2.0f, 2.0f) / olc::vf2d(pTarget->Size())); transformTarget.translate( olc::vf2d( - -1.0f + (1.0f / float(pTarget->Size().x)), - -1.0f + (1.0f / float(pTarget->Size().y)) + -1.0f,// +(1.0f / float(pTarget->Size().x)), + -1.0f// + (1.0f / float(pTarget->Size().y)) )); WorldReset(); @@ -152,7 +156,7 @@ olc::vf2d olc::Draw2D::ScreenToWorld(const olc::vf2d& v) const void Draw2D::Pixel(const olc::vf2d& pos, const olc::Pixel col) { // Check if in bounds - olc::vf2d tpos = transformTarget.forward(pos); + olc::vf2d tpos = transformAffine.forward(pos); if (tpos.x >= 0 && tpos.y >= 0 && tpos.x < pTarget->Size().x && tpos.y < pTarget->Size().y) { PrepareTargetForSW(); @@ -168,6 +172,12 @@ olc::Pixel olc::Draw2D::GetPixel(olc::Image& image, const olc::vf2d& pos) return image.Pixel(pos); } +void olc::Draw2D::Clear(const olc::Pixel& col) +{ + //PrepareImageForHW(*pTarget); + pRenderer->ClearViewport(col, true, true); +} + GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::vector& vPoints, const std::vector& vColours, const olc::Pixel tint) { GPUTask task; @@ -186,7 +196,7 @@ GPUTask olc::Draw2D::TaskDrawPolygon(GPUTask::Structure structure, const std::ve task.structure = structure; task.bWireframe = true; for (const auto& v : vPoints) - task.vertexBuffer.push_back({ v.x, v.y, 1.0f, 1.0f, colour, 0, 0, 0,0, 0, 0, 0, 0 }); + task.vertexBuffer.push_back({ v.x+0.0f, v.y+0.0f, 1.0f, 1.0f, colour, 0, 0, 0,0, 0, 0, 0, 0 }); task.tint = tint; return task; } @@ -233,7 +243,8 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel return vecGPUTasks.emplace_back( TaskDrawPolygon( GPUTask::Structure::Line, - transformCombined.transform({ p1, p2 }), + //transformCombined.transform({ p1, p2 }), + {p1, p2}, col, olc::Colour::WHITE )); @@ -253,14 +264,38 @@ GPUTask Draw2D::Line(const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel GPUTask olc::Draw2D::Rect(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col) { + // Right a big, hearty, F&^% you to OpenGL's Diamond Exit Strategy. It makes line drawing + // with OpenGL a smidge unreliable + + // Check if its axis aligned + if (std::abs(transformAffine.rotate()) < 0.0001f) + { + // SW Raster the line + } + PrepareTargetForHW(); return vecGPUTasks.emplace_back( TaskDrawPolygon( GPUTask::Structure::Fan, - transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + transformAffine.forward({ + olc::vf2d( pos.x + 0.0f, pos.y + 0.0f ), + olc::vf2d( pos.x + size.x +0.0f, pos.y + 0.0f ), + + //olc::vf2d( pos.x + size.x + 0.0f, pos.y + 0.0f), + olc::vf2d( pos.x + size.x + 0.0f, pos.y + size.y + 0.0f ), + + //olc::vf2d( pos.x + size.x + 0.0f, pos.y + size.y + 0.0f), + olc::vf2d( pos.x + 0.0f, pos.y + size.y + 0.0f ), + + //olc::vf2d( pos.x + 0.0f, pos.y + size.y + 0.0f), + //olc::vf2d( pos.x + 0.0f, pos.y + 0.0f), + }), + + // transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), col, olc::Colour::WHITE )); + } @@ -270,7 +305,9 @@ GPUTask olc::Draw2D::FilledRect(const olc::vf2d& pos, const olc::vf2d& size, con return vecGPUTasks.emplace_back( TaskFillPolygon( GPUTask::Structure::Fan, - transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + //transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + { { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, + col, olc::Colour::WHITE )); @@ -288,8 +325,8 @@ GPUTask olc::Draw2D::Image(olc::ImageRegion image, const olc::vf2d& pos, const o return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, - transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), - //{ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, + //transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + { { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, // Tex coords are clockwise { image.coords[0], image.coords[1], image.coords[2], image.coords[3]}, @@ -318,7 +355,8 @@ GPUTask olc::Draw2D::ImageRotated(olc::ImageRegion image, const olc::vf2d& pos, return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, - transformCombined.transform(vPoints), + //transformCombined.transform(vPoints), + vPoints, { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, { image.coords[0], image.coords[1], image.coords[2], image.coords[3] }, &image.image @@ -360,7 +398,8 @@ GPUTask olc::Draw2D::ImageQuad(olc::ImageRegion image, const olc::vf2d& vTL, con return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, - transformCombined.transform({ vTL, vTR, vBR, vBL }), + //transformCombined.transform({ vTL, vTR, vBR, vBL }), + { vTL, vTR, vBR, vBL }, { {q[0], 1.0f}, {q[1], 1.0f}, {q[2], 1.0f}, {q[3], 1.0f} }, { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, { image.coords[0] * q[0], image.coords[1] * q[1], image.coords[2] * q[2], image.coords[3] * q[3] }, @@ -387,11 +426,11 @@ GPUTask olc::Draw2D::ImageRect(olc::ImageRegion image, const olc::vf2d& pos, con return vecGPUTasks.emplace_back( TaskTexturedPolygon( GPUTask::Structure::Fan, - transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), - //{ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, + //transformCombined.transform({ { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }), + { { pos.x, pos.y }, { pos.x + size.x, pos.y }, { pos.x + size.x, pos.y + size.y }, { pos.x, pos.y + size.y } }, { olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE, olc::Colour::WHITE }, // Tex coords are clockwise - { image.coords[0], image.coords[1], image.coords[2], image.coords[3] }, + { image.coords[3], image.coords[2], image.coords[1], image.coords[0] }, &image.image )); } diff --git a/dev/src/draw2d.h b/dev/src/draw2d.h index 9e453106..b549381c 100644 --- a/dev/src/draw2d.h +++ b/dev/src/draw2d.h @@ -71,6 +71,7 @@ namespace olc const olc::vf2d& pos); // Clear + void Clear(const olc::Pixel& col); public: // Draws a single pixel wide line diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index 50298b10..ad918ef5 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -134,19 +134,47 @@ namespace olc::gpu "layout(location = 1) in vec4 aCol;\n" "layout(location = 2) in vec2 aTex;\n" "uniform mat4 mvp;\n" - "uniform int is3d;\n" + "uniform int drawtype;\n" "uniform vec4 tint;\n" + "uniform vec2 target;\n" + "uniform vec2 invtarget;\n" "out vec2 oTex;\n" "out vec4 oCol;\n" - "void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex;} oCol = aCol * tint;}" + "void main()\n" + "{\n " + " if(drawtype == 2)\n // 3D\n " + " {\n " + " gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n " + " oTex = aTex;\n " + " }\n " + "\n" + " else if(drawtype == 1)\n // Line\n " + " {\n " + " float p = 1.0 / aPos.z;\n " + " gl_Position = p * vec4(2.0 * ((floor(aPos.x) + 0.5) * invtarget.x) - 1.0,2.0 * ((floor(aPos.y)+0.5) * invtarget.y) - 1.0, 0.0, 1.0);\n " + " oTex = p * vec2(aTex.x, aTex.y);\n " + " }\n " + "" + " else if(drawtype == 0)\n // Quad\n " + " {\n " + " float p = 1.0 / aPos.z;\n " + " gl_Position = p * vec4(2.0 * ((floor(aPos.x)) * invtarget.x) - 1.0,2.0 * ((floor(aPos.y)) * invtarget.y) - 1.0, 0.0, 1.0);\n " + " oTex = p * vec2(aTex.x, aTex.y);\n " + " } else {gl_Position = aPos;}\n " + " \n " + " \n " + " oCol = aCol * tint;\n " + "}\n" //"void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = mvp * (p * vec4(aPos.x, aPos.y, 0.0, 1.0)); oTex = p * aTex;} oCol = aCol * tint;}" ); shaderDefault.Compile(); shaderDefault.CreateUniform("mvp"); - shaderDefault.CreateUniform("is3d"); + shaderDefault.CreateUniform("drawtype"); shaderDefault.CreateUniform("tint"); + shaderDefault.CreateUniform("target"); + shaderDefault.CreateUniform("invtarget"); // Create "Default" Vertex Buffer / Vertex Attributes. This buffer is reused // for all drawing operations. It's possible future versions may allow the @@ -320,6 +348,8 @@ namespace olc::gpu gl.glDrawBuffers(1, attachments.data()); // Bind buffers to textures gl.glFramebufferTexture2D(36160U, 36064U + slot, GL_TEXTURE_2D, texid, 0); + + return true; } @@ -347,7 +377,9 @@ namespace olc::gpu { case GPUTask::Task::DrawPolygon: { + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //gl.glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); if (task.pImage == nullptr) AssignTextureSource(0, imgBlank.GetGPUID()); @@ -361,8 +393,7 @@ namespace olc::gpu // Copy data from CPU to GPU gl.glBufferData(0x8892, sizeof(GPUTask::Vertex) * task.vertexBuffer.size(), task.vertexBuffer.data(), 0x88E0); - // Shader: Configure Rendering Mode - gl.glUniform1i(shaderDefault.GetUniform("is3d"), 0); + // Shader: Apply MVP Matrix //gl.glUniformMatrix4fv(shaderDefault.GetUniform("mvp"), 1, true, task.mvpMatrix.data()); @@ -376,34 +407,44 @@ namespace olc::gpu }; gl.glUniform4fv(shaderDefault.GetUniform("tint"), 1, f); - // Apply Culling modes - if (task.cullmode == GPUTask::CullMode::None) - { - gl.glCullFace(GL_FRONT); - gl.glDisable(GL_CULL_FACE); - } - else if (task.cullmode == GPUTask::CullMode::ClockWise) - { - gl.glCullFace(GL_FRONT); - gl.glEnable(GL_CULL_FACE); - } - else if (task.cullmode == GPUTask::CullMode::CounterClockWise) - { - gl.glCullFace(GL_BACK); - gl.glEnable(GL_CULL_FACE); - } + f[0] = 64.0f; + f[1] = 64.0f; + gl.glUniform2fv(shaderDefault.GetUniform("target"), 1, vTargetSize.a().data()); + gl.glUniform2fv(shaderDefault.GetUniform("invtarget"), 1, ((1.0f / vTargetSize)).a().data()); - // Apply Depth Testing (if required) - if (task.bDepth) - gl.glEnable(GL_DEPTH_TEST); + // Apply Culling modes + //if (task.cullmode == GPUTask::CullMode::None) + //{ + // gl.glCullFace(GL_FRONT); + // gl.glDisable(GL_CULL_FACE); + //} + //else if (task.cullmode == GPUTask::CullMode::ClockWise) + //{ + // gl.glCullFace(GL_FRONT); + // gl.glEnable(GL_CULL_FACE); + //} + //else if (task.cullmode == GPUTask::CullMode::CounterClockWise) + //{ + // gl.glCullFace(GL_BACK); + // gl.glEnable(GL_CULL_FACE); + //} + + //// Apply Depth Testing (if required) + //if (task.bDepth) + // gl.glEnable(GL_DEPTH_TEST); // Draw the thing! if (task.bWireframe) { + // Shader: Configure Rendering Mode + gl.glUniform1i(shaderDefault.GetUniform("drawtype"), 1); gl.glDrawArrays(GL_LINE_LOOP, 0, (GLsizei)task.vertexBuffer.size()); } else { + // Shader: Configure Rendering Mode + gl.glUniform1i(shaderDefault.GetUniform("drawtype"), 0); + if (task.structure == GPUTask::Structure::Fan) gl.glDrawArrays(GL_TRIANGLE_FAN, 0, (GLsizei)task.vertexBuffer.size()); else if (task.structure == GPUTask::Structure::Strip) @@ -412,6 +453,8 @@ namespace olc::gpu gl.glDrawArrays(GL_TRIANGLES, 0, (GLsizei)task.vertexBuffer.size()); else if (task.structure == GPUTask::Structure::Line) gl.glDrawArrays(GL_LINES, 0, (GLsizei)task.vertexBuffer.size()); + else if (task.structure == GPUTask::Structure::Point) + gl.glDrawArrays(GL_POINTS, 0, (GLsizei)task.vertexBuffer.size()); } if (task.bDepth) @@ -436,6 +479,7 @@ namespace olc::gpu { auto& gl = olc::apis::opengl::gl::Get(); gl.glViewport(int(pos.x), int(pos.y), int(size.x), int(size.y)); + vTargetSize = size; return true; } diff --git a/dev/src/gpu_opengl33.h b/dev/src/gpu_opengl33.h index 53f16f51..175ab14e 100644 --- a/dev/src/gpu_opengl33.h +++ b/dev/src/gpu_opengl33.h @@ -66,6 +66,7 @@ namespace olc uint32_t nDefaultVA = 0; uint32_t nDefaultFBO = 0; olc::Image imgBlank; + olc::vf2d vTargetSize; }; } diff --git a/dev/src/image.cpp b/dev/src/image.cpp index 46ad8a12..f84d5766 100644 --- a/dev/src/image.cpp +++ b/dev/src/image.cpp @@ -15,7 +15,7 @@ namespace olc { dimensions = size; config = cfg; - pixels.resize(dimensions.area(), olc::Pixel(255, 165, 0)); + pixels.resize(dimensions.area(), olc::Colour::TANGERINE); return true; } diff --git a/dev/src/window.cpp b/dev/src/window.cpp index b1b7c3bc..35d17abd 100644 --- a/dev/src/window.cpp +++ b/dev/src/window.cpp @@ -90,7 +90,7 @@ namespace olc gpu->AssignTextureTarget(0, imgPrimary.GetGPUID()); gpu->SetViewport({ 0,0 }, imgPrimary.Size()); - gpu->ClearViewport(olc::Colour::BLACK, true, true); + //gpu->ClearViewport(olc::Colour::BLACK, true, true); gpu->ApplyDefaultShader(); @@ -112,9 +112,10 @@ namespace olc // Take the window's completed "screen" and draw it as a textured quad to the backbuffer gpu->AssignTextureTarget(0, 0); gpu->SetViewport({ 0,0 }, GetSize()); - gpu->ClearViewport(olc::Colour::BLANK, true, true); + gpu->ClearViewport(olc::Colour::MAGENTA, true, true); draw.ClearTransform(); - draw.ImageRect(imgPrimary, { -1.0,1.0 }, { 2.0f,-2.0f }); + //draw.ImageRect(imgPrimary, { -1.0,1.0 }, { 2.0f,-2.0f }); + draw.ImageRect(imgPrimary, { 0.0,0.0 }, GetSize()); draw.ProcessGPUTasks(); // Update Window's primary surface diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index be67b500..febf1500 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -1,6 +1,8 @@ #define OLC_PGE_APPLICATION #include "olcpge3.h" + + class Example : public olc::PixelGameEngine { public: @@ -12,6 +14,34 @@ class Example : public olc::PixelGameEngine olc::Image imTest; olc::Image imLogo; + olc::Image imTemp; + + olc::Image imSampleTest; + + void CreateSampleTestImage(olc::Image& image, const olc::vi2d& s) + { + CreateImage(image, s); + draw.SetTarget(image); + + draw.Clear(olc::Colour::WHITE); + + std::vector vColours = { + olc::Colour::RED, + olc::Colour::YELLOW, + olc::Colour::GREEN, + olc::Colour::CYAN, + olc::Colour::BLUE, + olc::Colour::MAGENTA, + }; + + for (int i = 0; i < s.x/2; i++) + { + draw.Rect(olc::vi2d{ i,i }, s - olc::vi2d{ (i * 2)+1 ,(i * 2)+1 }, vColours[i % vColours.size()]); + } + + draw.Pixel({ 0.0,1 }, olc::Colour::BLACK); + + } float fAngle = 0.0f; @@ -36,6 +66,9 @@ class Example : public olc::PixelGameEngine //CreateImage(imTest, { 64,64 }); CreateImageFromFile(imLogo, "../tests/olc.png"); + CreateSampleTestImage(imSampleTest, { 33, 33 }); + + CreateImage(imTemp, { 64, 64 }); size_t x = 1; vecLogos.resize(x); @@ -47,10 +80,10 @@ class Example : public olc::PixelGameEngine } vecVerts = { - {200.0f, 200.0f}, + { 200.0f, 200.0f}, { 400.0f, 200.0f}, { 400.0f, 400.0f}, - {200.0f, 400.0f} + { 200.0f, 400.0f} }; return true; @@ -58,8 +91,36 @@ class Example : public olc::PixelGameEngine bool OnUserUpdate(float fElapsedTime) override { - fAngle += 0.1f * fElapsedTime; - draw.WorldRotate(fAngle, imgPrimary.Size() / 2.0f); + //draw.SetTarget(imTemp); + //draw.Clear(olc::Colour::BLANK); + //draw.FilledRect({ 20,5 }, { 6, 54 }, olc::Colour::GREEN); + //draw.FilledRect({ 0,0 }, imTemp.Size(), olc::Colour::BLANK); + + + //draw.SetTarget(imgPrimary); + //draw.Clear(olc::Colour::BLUE); + + + //draw.WorldReset(); + //draw.FilledRect({ 0,0 }, imgPrimary.Size() * olc::vf2d(0.5f, 1.0f), olc::Pixel(0, 0, 0, 1)); + + + draw.Clear(olc::Colour::VERY_DARK_BLUE); + + if (mouse.GetButton(1).bHeld) + { + fAngle += 0.2f * fElapsedTime; + draw.WorldRotate(fAngle, imgPrimary.Size() / 2.0f); + } + //for (int x = 0; x < imgPrimary.Size().x; x++) + // for (int y = 0; y < imgPrimary.Size().y; y++) + // draw.Pixel(olc::vf2d( x, y ), olc::Pixel(rand() % 255, rand() % 255, rand() % 255)); + + //// + //return true; + + + //std::cout << mouse.GetPosition() << "\n"; auto vMouse = draw.ScreenToWorld(mouse.GetPosition()); if (mouse.GetButton(0).bPressed) @@ -78,6 +139,8 @@ class Example : public olc::PixelGameEngine nSelectedVert = idx; } + + if (nSelectedVert != -1 && mouse.GetButton(0).bHeld) vecVerts[nSelectedVert] = vMouse; @@ -91,7 +154,20 @@ class Example : public olc::PixelGameEngine draw.Line(vecVerts[2], vecVerts[3], olc::Colour::MAGENTA); draw.Line(vecVerts[3], vecVerts[0], olc::Colour::MAGENTA); + //draw.Image(imTemp, vMouse, { 4,4 }); + + draw.Image(imSampleTest, vMouse); + + + //draw.Pixel(vMouse, olc::Colour::GREEN); + //draw.Line(vMouse, vMouse + 1, olc::Colour::GREEN); + draw.FilledRect({ 5,5 }, { 10,10 }, olc::Colour::YELLOW); + draw.Rect({ 8,8 }, { 20,20 }, olc::Colour::RED); + if(mouse.GetButton(0).bHeld) + draw.Line({ 1.0f, 1.0f }, { 25.5f, 25.5f }); + + //draw.Rect(vMouse, { 100,100 }); /*for (auto& a : vecLogos) { @@ -218,7 +294,14 @@ int main() { Example demo; //if (demo.Construct({ 256, 240 }, { 4, 4 })) - if (demo.Construct({ 1280, 960 }, { 1, 1 })) + + olc::PGEConfig cfg; + cfg.vPixelSize = { 16,16 }; + cfg.vScreenSize = { 64, 64 }; + //cfg.bVSync = true; + + //if (demo.Construct({ 1280, 960 }, { 1, 1 }, cfg)) + if(demo.Construct(cfg)) demo.Start(); return 0; From 1330be9eda9b11e340e88470513cce11fa477879 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Thu, 25 Sep 2025 22:45:43 +0100 Subject: [PATCH 11/11] entidyfication of the shades --- dev/src/gpu_opengl33.cpp | 147 ++++++++++++++++++++++++++------------- dev/tests/test_mh.cpp | 4 +- 2 files changed, 100 insertions(+), 51 deletions(-) diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index ad918ef5..52f20bd1 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -119,55 +119,104 @@ namespace olc::gpu // Create "Default" Shader - shaderDefault.SetPixelShaderSource( - "#version 330 core\n" - "layout(location = 0) out vec4 pixel;\n" - "in vec2 oTex;\n" - "in vec4 oCol;\n" - "uniform sampler2D sprTex;\n" - "void main(){pixel = texture(sprTex, oTex) * oCol;}" - ); - - shaderDefault.SetVertexShaderSource( - "#version 330 core\n" - "layout(location = 0) in vec4 aPos;\n" - "layout(location = 1) in vec4 aCol;\n" - "layout(location = 2) in vec2 aTex;\n" - "uniform mat4 mvp;\n" - "uniform int drawtype;\n" - "uniform vec4 tint;\n" - "uniform vec2 target;\n" - "uniform vec2 invtarget;\n" - "out vec2 oTex;\n" - "out vec4 oCol;\n" - "void main()\n" - "{\n " - " if(drawtype == 2)\n // 3D\n " - " {\n " - " gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n " - " oTex = aTex;\n " - " }\n " - "\n" - " else if(drawtype == 1)\n // Line\n " - " {\n " - " float p = 1.0 / aPos.z;\n " - " gl_Position = p * vec4(2.0 * ((floor(aPos.x) + 0.5) * invtarget.x) - 1.0,2.0 * ((floor(aPos.y)+0.5) * invtarget.y) - 1.0, 0.0, 1.0);\n " - " oTex = p * vec2(aTex.x, aTex.y);\n " - " }\n " - "" - " else if(drawtype == 0)\n // Quad\n " - " {\n " - " float p = 1.0 / aPos.z;\n " - " gl_Position = p * vec4(2.0 * ((floor(aPos.x)) * invtarget.x) - 1.0,2.0 * ((floor(aPos.y)) * invtarget.y) - 1.0, 0.0, 1.0);\n " - " oTex = p * vec2(aTex.x, aTex.y);\n " - " } else {gl_Position = aPos;}\n " - " \n " - " \n " - " oCol = aCol * tint;\n " - "}\n" - //"void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = mvp * (p * vec4(aPos.x, aPos.y, 0.0, 1.0)); oTex = p * aTex;} oCol = aCol * tint;}" - - ); + shaderDefault.SetPixelShaderSource(R"( + #version 330 core + layout(location = 0) out vec4 pixel; + in vec2 oTex; + in vec4 oCol; + uniform sampler2D sprTex; + + void main() + { + pixel = texture(sprTex, oTex) * oCol; + } + )"); + + shaderDefault.SetVertexShaderSource(R"( + #version 330 core + layout(location = 0) in vec4 aPos; + layout(location = 1) in vec4 aCol; + layout(location = 2) in vec2 aTex; + uniform mat4 mvp; + uniform int drawtype; + uniform vec4 tint; + uniform vec2 target; + uniform vec2 invtarget; + out vec2 oTex; + out vec4 oCol; + + void main() + { + if(drawtype == 2) // 3D + { + gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); + oTex = aTex; + } + + else if(drawtype == 1) // 2D Line + { + float p = 1.0 / aPos.z; + gl_Position = p * vec4(vec2(2.0 * ((floor(aPos.xy) + 0.5) * invtarget) - 1.0), 0.0, 1.0); + oTex = aTex; + } + + else if(drawtype == 0) // 2D Polygon + { + float p = 1.0 / aPos.z; + gl_Position = p * vec4(vec2(2.0 * ((floor(aPos.xy)) * invtarget) - 1.0), 0.0, 1.0); + oTex = p * vec2(aTex.x, aTex.y); + } + + else // Balanced default + { + gl_Position = aPos; + oTex = aTex; + } + + oCol = aCol * tint; + } + )"); + + //shaderDefault.SetVertexShaderSource( + // "#version 330 core\n" + // "layout(location = 0) in vec4 aPos;\n" + // "layout(location = 1) in vec4 aCol;\n" + // "layout(location = 2) in vec2 aTex;\n" + // "uniform mat4 mvp;\n" + // "uniform int drawtype;\n" + // "uniform vec4 tint;\n" + // "uniform vec2 target;\n" + // "uniform vec2 invtarget;\n" + // "out vec2 oTex;\n" + // "out vec4 oCol;\n" + // "void main()\n" + // "{\n " + // " if(drawtype == 2)\n // 3D\n " + // " {\n " + // " gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n " + // " oTex = aTex;\n " + // " }\n " + // "\n" + // " else if(drawtype == 1)\n // Line\n " + // " {\n " + // " float p = 1.0 / aPos.z;\n " + // " gl_Position = p * vec4(2.0 * ((floor(aPos.x) + 0.5) * invtarget.x) - 1.0,2.0 * ((floor(aPos.y)+0.5) * invtarget.y) - 1.0, 0.0, 1.0);\n " + // " oTex = p * vec2(aTex.x, aTex.y);\n " + // " }\n " + // "" + // " else if(drawtype == 0)\n // Quad\n " + // " {\n " + // " float p = 1.0 / aPos.z;\n " + // " gl_Position = p * vec4(2.0 * ((floor(aPos.x)) * invtarget.x) - 1.0,2.0 * ((floor(aPos.y)) * invtarget.y) - 1.0, 0.0, 1.0);\n " + // " oTex = p * vec2(aTex.x, aTex.y);\n " + // " } else {gl_Position = aPos;}\n " + // " \n " + // " \n " + // " oCol = aCol * tint;\n " + // "}\n" + // //"void main(){ if(is3d!=0) {gl_Position = mvp * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTex = aTex;} else {float p = 1.0 / aPos.z; gl_Position = mvp * (p * vec4(aPos.x, aPos.y, 0.0, 1.0)); oTex = p * aTex;} oCol = aCol * tint;}" + + //); shaderDefault.Compile(); shaderDefault.CreateUniform("mvp"); diff --git a/dev/tests/test_mh.cpp b/dev/tests/test_mh.cpp index febf1500..eaaccc16 100644 --- a/dev/tests/test_mh.cpp +++ b/dev/tests/test_mh.cpp @@ -296,8 +296,8 @@ int main() //if (demo.Construct({ 256, 240 }, { 4, 4 })) olc::PGEConfig cfg; - cfg.vPixelSize = { 16,16 }; - cfg.vScreenSize = { 64, 64 }; + cfg.vPixelSize = { 4,4 }; + cfg.vScreenSize = { 256, 240 }; //cfg.bVSync = true; //if (demo.Construct({ 1280, 960 }, { 1, 1 }, cfg))