diff --git a/.gitignore b/.gitignore index 2f86d11..a89c4ad 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,5 @@ examples/xdg-shell.o # stb image headerss stb_image_write.h stb_image.h +/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets/x64/Debug +/dev/msvc/olcPGE3_wxWidgets/x64/Debug diff --git a/dev/msvc/olcPGE3.sln b/dev/msvc/olcPGE3.sln index 33b66c2..b18666d 100644 --- a/dev/msvc/olcPGE3.sln +++ b/dev/msvc/olcPGE3.sln @@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "olcPGE3", "olcPGE3.vcxproj" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "olcPGE3_BuildSH", "olcPGE3_BuildSH\olcPGE3_BuildSH.vcxproj", "{227300C2-9BC8-4E66-95FC-334A009D449B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "olcPGE3_wxWidgets", "olcPGE3_wxWidgets\olcPGE3_wxWidgets.vcxproj", "{B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -31,6 +33,14 @@ Global {227300C2-9BC8-4E66-95FC-334A009D449B}.Release|x64.Build.0 = Release|x64 {227300C2-9BC8-4E66-95FC-334A009D449B}.Release|x86.ActiveCfg = Release|Win32 {227300C2-9BC8-4E66-95FC-334A009D449B}.Release|x86.Build.0 = Release|Win32 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Debug|x64.ActiveCfg = Debug|x64 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Debug|x64.Build.0 = Debug|x64 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Debug|x86.ActiveCfg = Debug|Win32 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Debug|x86.Build.0 = Debug|Win32 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Release|x64.ActiveCfg = Release|x64 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Release|x64.Build.0 = Release|x64 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Release|x86.ActiveCfg = Release|Win32 + {B87BDA1C-BB21-486C-BEB1-7C33AF2442C0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/dev/msvc/olcPGE3.vcxproj b/dev/msvc/olcPGE3.vcxproj index 598c815..fcff341 100644 --- a/dev/msvc/olcPGE3.vcxproj +++ b/dev/msvc/olcPGE3.vcxproj @@ -234,6 +234,10 @@ true + + true + true + @@ -258,6 +262,7 @@ true true + @@ -315,6 +320,10 @@ true + + true + true + @@ -356,8 +365,12 @@ + + + + diff --git a/dev/msvc/olcPGE3.vcxproj.filters b/dev/msvc/olcPGE3.vcxproj.filters index 2323331..03573c3 100644 --- a/dev/msvc/olcPGE3.vcxproj.filters +++ b/dev/msvc/olcPGE3.vcxproj.filters @@ -49,6 +49,18 @@ {76f094ac-5176-4402-9395-6187374c5d64} + + {eb0bb606-e8b0-419b-b621-b61633c50add} + + + {12be6a62-5486-49fa-be63-b305888e2aca} + + + {6b6f0117-0e7e-4dc8-ad83-96525e679ff3} + + + {799e6b1b-18e3-48e9-9181-a7e139ebd5da} + @@ -144,9 +156,6 @@ Header Files - - Hosts - GPUs @@ -171,15 +180,24 @@ Hardware - - Hosts - Header Files Utilities + + Header Files + + + Header Files + + + Hosts + + + Hosts\wxWidgets Specific + @@ -257,6 +275,9 @@ Hardware + + Hosts\wxWidgets Specific + @@ -265,6 +286,18 @@ Extras + + Extensions + + + Extensions\MiniAudio + + + Extensions\SplashScreen + + + Utilities + diff --git a/dev/msvc/olcPGE3_wxWidgets/cApp.cpp b/dev/msvc/olcPGE3_wxWidgets/cApp.cpp new file mode 100644 index 0000000..eebc29a --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/cApp.cpp @@ -0,0 +1,19 @@ +#include "cApp.h" +#include "cMain.h" + + + +wxIMPLEMENT_APP(cApp); + +bool cApp::OnInit() +{ + if (!wxApp::OnInit()) + return false; + + cMain* pMain = new cMain(); + pMain->Show(true); + SetTopWindow(pMain); + + return true; +} + diff --git a/dev/msvc/olcPGE3_wxWidgets/cApp.h b/dev/msvc/olcPGE3_wxWidgets/cApp.h new file mode 100644 index 0000000..7752604 --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/cApp.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +class cApp : public wxApp +{ +public: + virtual bool OnInit() override; +}; + +wxDECLARE_APP(cApp); + diff --git a/dev/msvc/olcPGE3_wxWidgets/cMain.cpp b/dev/msvc/olcPGE3_wxWidgets/cMain.cpp new file mode 100644 index 0000000..17accab --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/cMain.cpp @@ -0,0 +1,127 @@ +#include "cMain.h" + + +ExamplePanel1::ExamplePanel1(wxWindow* pParent) : olc::wx::PGE3Panel(pParent) +{ + vLineStart = { 0,0 }; + vLineStop = { 256, 240 }; +} + +void ExamplePanel1::OnRender() +{ + draw.Line(vLineStart, olc::Colour::BLUE, vLineStop, olc::Colour::RED); + draw.StringProp({ 10, 2 }, "olc::PixelGameEngine\nin\nwxWidgets!", olc::Colour::WHITE); +} + +void ExamplePanel1::OnMouseLeftDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) +{ + vLineStart = vWorldPos; + Refresh(); +} + +void ExamplePanel1::OnMouseRightDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) +{ + vLineStop = vWorldPos; + Refresh(); +} + + + + + + +ExamplePanel2::ExamplePanel2(wxWindow* pParent) : olc::wx::PGE3Panel(pParent) +{ + +} + +ExamplePanel2::ExamplePanel2(wxWindow* pParent, const olc::vi2d& vFixedSize) : olc::wx::PGE3Panel(pParent, vFixedSize) +{ + +} + +void ExamplePanel2::OnCreate() +{ + + vPos = { 100,100 }; + vVel = olc::vf2d(100.0f, 1.0f).cart(); +} + +void ExamplePanel2::OnRender() +{ + draw.Clear(olc::Colour::VERY_DARK_BLUE); + draw.FilledCircle(vPos.round(), 10, olc::Colour::WHITE); +} + +void ExamplePanel2::OnMouseMiddleDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) +{ + vPos = vWorldPos; +} + +void ExamplePanel2::OnUpdate(const float fElapsedTime) +{ + vPos += vVel * fElapsedTime; + + if (vPos.x - 10 <= 0) + { + vPos.x = 10; + vVel.x *= -1; + } + if (vPos.y - 10 <= 0) + { + vPos.y = 10; + vVel.y *= -1; + } + if (vPos.x + 10 >= draw.GetTargetSize().x) + { + vPos.x = draw.GetTargetSize().x - 10; + vVel.x *= -1; + } + + if (vPos.y + 10 >= draw.GetTargetSize().y) + { + vPos.y = draw.GetTargetSize().y - 10; + vVel.y *= -1; + } +} + + + +cMain::cMain() + : wxFrame(nullptr, wxID_ANY, "olcPGE3 wxWidgets", wxDefaultPosition, wxSize(800, 600), wxDEFAULT_FRAME_STYLE) +{ + + wxPanel* pRoot = new wxPanel(this); + wxBoxSizer* pSizer = new wxBoxSizer(wxHORIZONTAL); + + m_pPanel1 = new ExamplePanel1(pRoot); + pSizer->Add(m_pPanel1, 1, wxEXPAND | wxALL, 8); + + m_pPanel2 = new ExamplePanel2(pRoot); + m_pPanel2->OnCreate(); + pSizer->Add(m_pPanel2, 1, wxEXPAND | wxALL, 8); + + m_pPanel3 = new ExamplePanel2(pRoot, { 128,128 }); + m_pPanel3->OnCreate(); + pSizer->Add(m_pPanel3, 1, wxEXPAND | wxALL, 8); + + pRoot->SetSizer(pSizer); + + m_timer.Bind(wxEVT_TIMER, &cMain::OnTick, this); + m_timer.Start(1000 / 60); +} + +void cMain::OnTick(wxTimerEvent& event) +{ + olc_IgnoreUnused(event); + //m_pPanel1->OnUpdate(1.0f / 60.0f); + //m_pPanel1->Refresh(false); + + m_pPanel2->OnUpdate(1.0f / 60.0f); + m_pPanel2->Refresh(false); + + m_pPanel3->OnUpdate(1.0f / 60.0f); + m_pPanel3->Refresh(false); +} + + diff --git a/dev/msvc/olcPGE3_wxWidgets/cMain.h b/dev/msvc/olcPGE3_wxWidgets/cMain.h new file mode 100644 index 0000000..263d977 --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/cMain.h @@ -0,0 +1,57 @@ +#pragma once + +#define OLC_USE_WXWIDGETS +#include "..\..\..\olcPixelGameEngine3.h" + +class ExamplePanel1 : public olc::wx::PGE3Panel +{ +public: + ExamplePanel1(wxWindow* pParent); + +protected: + void OnRender() override; + + void OnMouseLeftDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) override; + void OnMouseRightDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) override; + +private: + olc::vf2d vLineStart; + olc::vf2d vLineStop; +}; + + +class ExamplePanel2 : public olc::wx::PGE3Panel +{ +public: + ExamplePanel2(wxWindow* pParent); + ExamplePanel2(wxWindow* pParent, const olc::vi2d& vFixedSize); + +public: + void OnUpdate(const float fElapsedTime) override; + void OnCreate() override; +protected: + void OnRender() override; + void OnMouseMiddleDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) override; + + +private: + olc::vf2d vPos; + olc::vf2d vVel; +}; + +class cMain : public wxFrame +{ +public: + cMain(); + +private: + void OnTick(wxTimerEvent& event); + + +private: + ExamplePanel1* m_pPanel1 = nullptr; + ExamplePanel2* m_pPanel2 = nullptr; + ExamplePanel2* m_pPanel3 = nullptr; + wxTimer m_timer; +}; + diff --git a/dev/msvc/olcPGE3_wxWidgets/make_pge3.bat b/dev/msvc/olcPGE3_wxWidgets/make_pge3.bat new file mode 100644 index 0000000..10a5794 --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/make_pge3.bat @@ -0,0 +1,4 @@ +@echo on +cd ..\..\src +..\..\..\olcGimmeHead\msvc\x64\debug\gimme-head.exe sh_template.h ..\..\olcPixelGameEngine3.h +rem copy ..\msvc\olcPGE3_BuildSH\olcPixelGameEngine3.h ..\..\olcPixelGameEngine3.h \ No newline at end of file diff --git a/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets.vcxproj b/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets.vcxproj new file mode 100644 index 0000000..7fc506e --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 18.0 + Win32Proj + {b87bda1c-bb21-486c-beb1-7c33af2442c0} + olcPGE3wxWidgets + 10.0 + + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + + + + + + + + + + + + + + + + + + + E:\sdks\wx333\include;E:\sdks\wx333\include\msvc;$(IncludePath) + E:\sdks\wx333\lib\vc_x64_lib;$(LibraryPath) + + + E:\sdks\wx333\include;E:\sdks\wx333\include\msvc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + E:\sdks\wx333\lib\vc_x64_lib;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + + + true + + + + + Level3 + true + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + stdcpp20 + + + Windows + true + + + true + + + $(ProjectDir)make_pge3.bat + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Windows + true + + + true + + + $(ProjectDir)make_pge3.bat + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets.vcxproj.filters b/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets.vcxproj.filters new file mode 100644 index 0000000..d26e64c --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/olcPGE3_wxWidgets.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/dev/msvc/olcPGE3_wxWidgets/wx_pge3.cpp b/dev/msvc/olcPGE3_wxWidgets/wx_pge3.cpp new file mode 100644 index 0000000..d268e00 --- /dev/null +++ b/dev/msvc/olcPGE3_wxWidgets/wx_pge3.cpp @@ -0,0 +1,3 @@ +#define OLC_USE_WXWIDGETS +#define OLC_PGE3_APPLICATION +#include "..\..\..\olcPixelGameEngine3.h" \ No newline at end of file diff --git a/dev/src/api_opengl.h b/dev/src/api_opengl.h index 4ba39a2..c6c120a 100644 --- a/dev/src/api_opengl.h +++ b/dev/src/api_opengl.h @@ -86,6 +86,11 @@ #define OGL_LOAD(t) reinterpret_cast(eglGetProcAddress(#t)) #endif +#if OLC_HOST == OLC_HOST_WXWIDGETS + + +#endif + #if !defined(CALLSTYLE) #define CALLSTYLE #endif diff --git a/dev/src/config.h b/dev/src/config.h index 60136e8..fb23c03 100644 --- a/dev/src/config.h +++ b/dev/src/config.h @@ -35,6 +35,7 @@ #define OLC_HOST_ANDROID 7 #define OLC_HOST_IOS 8 + #if !defined(OLC_HOST) #if defined(_WIN32) #define OLC_HOST OLC_HOST_WINDOWS @@ -123,6 +124,7 @@ #define OLC_IMAGELOADER OLC_IMAGELOADER_NDK_IMAGEDECODER #define OLC_IMAGELOADER_CLASS ImageLoader_NDKImageDecoder #endif + #endif // We wait until after the platform specific image loader is selected @@ -199,4 +201,5 @@ inline constexpr void olc_IgnoreUnused(Args&&...) noexcept {} #define OLC_FRIENDLY_HOST Host_Android #endif + //! END CONFIGURATION diff --git a/dev/src/core.cpp b/dev/src/core.cpp index 8b39c45..19da9c9 100644 --- a/dev/src/core.cpp +++ b/dev/src/core.cpp @@ -37,6 +37,10 @@ #include "host_android.h" #endif +#if OLC_HOST == OLC_HOST_WXWIDGETS +#include "host_wxwidgets.h" +#endif + #if OLC_IMAGELOADER == OLC_IMAGELOADER_WINGDI #include "imload_wingdi.h" #endif diff --git a/dev/src/font.cpp b/dev/src/font.cpp index be13d21..7660be8 100644 --- a/dev/src/font.cpp +++ b/dev/src/font.cpp @@ -7,7 +7,11 @@ namespace olc { namespace pgeguts { +#if defined(OLC_USE_WXWIDGETS) + void CreateClassicFont(olc::wx::PGE3Core* pge) +#else void CreateClassicFont(olc::PGEWindow* pge) +#endif { std::string data = "?Q`0001oOch0o01o@F40o000000000" diff --git a/dev/src/font.h b/dev/src/font.h index 6bb2976..9a03bc0 100644 --- a/dev/src/font.h +++ b/dev/src/font.h @@ -21,7 +21,15 @@ #if !defined(PGE_FONT_DECLARED) namespace olc { +#if defined(OLC_USE_WXWIDGETS) + namespace wx + { + class PGE3Core; + } +#else class PGEWindow; +#endif + struct FontGlyph { @@ -64,7 +72,11 @@ namespace olc namespace pgeguts { // Create the classic PGE font +#if defined(OLC_USE_WXWIDGETS) + void CreateClassicFont(olc::wx::PGE3Core* pge); +#else void CreateClassicFont(olc::PGEWindow* pge); +#endif } } diff --git a/dev/src/gpu_opengl33.cpp b/dev/src/gpu_opengl33.cpp index 66bc14b..5aea813 100644 --- a/dev/src/gpu_opengl33.cpp +++ b/dev/src/gpu_opengl33.cpp @@ -243,7 +243,8 @@ void main() config = cfg; - +#if !defined(OLC_USE_WXWIDGETS) + #if OLC_HOST == OLC_HOST_WINDOWS // Create OpenGL Device Context if (!PrepareWindowTarget(os_win_id)) @@ -376,6 +377,10 @@ void main() } #endif +#else // wxWidgets specific + +#endif // wxWidgets + // Can't load OpenGL API until context is loaded auto& gl = olc::apis::opengl::gl::Get(); if (!gl.HasLoaded()) @@ -786,6 +791,14 @@ void main() gl.glDeleteRenderbuffers(1, &rboId); mapTextureToRenderbuffer.erase(texid); } + + mapTextureSizes.erase(texid); + + if (nCurrentTextureSource == texid) + nCurrentTextureSource = 0; + + if (nCurrentTextureTarget == texid) + nCurrentTextureTarget = 0; return true; } diff --git a/dev/src/host_wxwidgets.cpp b/dev/src/host_wxwidgets.cpp new file mode 100644 index 0000000..6585448 --- /dev/null +++ b/dev/src/host_wxwidgets.cpp @@ -0,0 +1,332 @@ +#include "host_wxwidgets.h" + + +//! START IMPLEMENTATION +namespace olc::wx +{ + PGE3Core::PGE3Core(wxWindow* parent) : wxGLCanvas(parent, -1, nullptr) + { + // Create a wxWidgets "glContext" targeting OpenGL 3.3 + wxGLContextAttrs ctxAttrs; + ctxAttrs.CoreProfile().OGLVersion(3, 3).EndList(); + m_glContext = new wxGLContext(this, NULL, &ctxAttrs); + SetCurrent(*m_glContext); + + + // Create all the vital parts of PGE + pImageLoader = std::make_unique(); + + // Create the renderer + olc::gpu::RendererConfig cfgRenderer; + pRenderer = std::make_unique(); + pRenderer->CreateDevice({ this }, cfgRenderer); + + // Load the font + olc::pgeguts::CreateClassicFont(this); + + // wxWidgets should hide this pseudo-canvas. It was only + // needed to get the context + this->Hide(); + } + + PGE3Core::~PGE3Core() + { + delete m_glContext; + } + + bool PGE3Core::CreateImage(olc::Image& image, const olc::vi2d& size, const ImageConfig& cfg) + { + // Create CPU Image + if (!image.CreateNoGPU(size, cfg)) + return false; + + // Create GPU Image + auto id = pRenderer->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.CreateNoGPU({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + + bool PGE3Core::CreateImageFromFile(olc::Image& image, const std::string& sFileName, const ImageConfig& cfg) + { + if (pImageLoader->CreateImageFromFile(image, sFileName)) + { + // Image has loaded ok, and populated into pixel vector + // + // Create GPU Image + auto id = pRenderer->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.CreateNoGPU({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + + return false; + } + + bool PGE3Core::CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes, const ImageConfig& cfg) + { + if (pImageLoader->CreateImageFromMemory(image, data, bytes)) + { + // Image has loaded ok, and populated into pixel vector + // + // Create GPU Image + auto id = pRenderer->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.CreateNoGPU({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + + std::cout << "Create From Memory Failed\n"; + return false; + } + + bool PGE3Core::WriteImageToFile(const olc::Image& image, const std::string& sFileName) + { + olc_IgnoreUnused(image, sFileName); + return false; + } + + void PGE3Core::DestroyImage(olc::Image& image) + { + // If image has gpu resource, remove it + if (image.GetGPUID() != 0) + { + pRenderer->DeleteTexture(uint32_t(image.GetGPUID())); + image.SetGPUID(0); + } + + // Free any cpu memory associated with image + image.CreateNoGPU({ 0,0 }); + } + + wxGLContext* PGE3Core::get() const + { + return m_glContext; + } + + olc::gpu::Renderer* PGE3Core::GetRenderer() + { + return pRenderer.get(); + } + + olc::imload::ImageLoader* PGE3Core::GetImageLoader() + { + return pImageLoader.get(); + } + + + + olc::wx::PGE3Core* PGE3Panel::m_pCore = nullptr; + + + + PGE3Panel::PGE3Panel(wxWindow* parent) : wxGLCanvas(parent, -1, nullptr) + { + if (m_pCore == nullptr) + { + // Create a static PGE3Core + m_pCore = new PGE3Core(this); + } + + // Set the context via wxWidgets + SetCurrent(*m_pCore->get()); + + // Associate this instance of draw with the renderer + draw.SetGPU(m_pCore->GetRenderer()); + + // Create the default draw target + bFixedSize = false; + m_pCore->CreateImage(imgPrimary, { 256, 240 }); + + ResetDrawState(); + + Connect(wxEVT_PAINT, wxPaintEventHandler(olc::wx::PGE3Panel::Event_OnPaint)); + Connect(wxEVT_SIZE, wxSizeEventHandler(olc::wx::PGE3Panel::Event_OnResize)); + Connect(wxEVT_MOTION, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMove)); + Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleDown)); + Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleUp)); + Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseWheel)); + Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftDown)); + Connect(wxEVT_LEFT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftUp)); + Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightDown)); + Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightUp)); + } + + PGE3Panel::PGE3Panel(wxWindow* parent, const olc::vi2d& vFixedSize) : wxGLCanvas(parent, -1, nullptr) + { + if (m_pCore == nullptr) + { + // Create a static PGE3Core + m_pCore = new PGE3Core(this); + } + + // Set the context via wxWidgets + SetCurrent(*m_pCore->get()); + + // Associate this instance of draw with the renderer + draw.SetGPU(m_pCore->GetRenderer()); + + // Create the default draw target + vFixedSizeImage = vFixedSize; + bFixedSize = true; + m_pCore->CreateImage(imgPrimary, vFixedSize); + + ResetDrawState(); + + Connect(wxEVT_PAINT, wxPaintEventHandler(olc::wx::PGE3Panel::Event_OnPaint)); + Connect(wxEVT_MOTION, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMove)); + Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleDown)); + Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleUp)); + Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseWheel)); + Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftDown)); + Connect(wxEVT_LEFT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftUp)); + Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightDown)); + Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightUp)); + } + + PGE3Panel::~PGE3Panel() + { + Disconnect(wxEVT_PAINT, wxPaintEventHandler(olc::wx::PGE3Panel::Event_OnPaint)); + Disconnect(wxEVT_SIZE, wxSizeEventHandler(olc::wx::PGE3Panel::Event_OnResize)); + Disconnect(wxEVT_MOTION, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMove)); + Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleDown)); + Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleUp)); + Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseWheel)); + Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftDown)); + Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftUp)); + Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightDown)); + Disconnect(wxEVT_RIGHT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightUp)); + } + + void PGE3Panel::ResetDrawState() + { + // Set the context via wxWidgets + SetCurrent(*m_pCore->get()); + m_pCore->GetRenderer()->ApplyDefaultShader(); + draw.SetTarget(imgPrimary); + draw.WorldReset(); + draw.SetBlendMode(olc::BlendMode::Alpha); + draw.SetCullMode(olc::CullMode::None); + } + + + + void PGE3Panel::Event_OnPaint(wxPaintEvent& evt) + { + // Configure WX to render this window + wxPaintDC(this); + + // Perform actual render + ResetDrawState(); + OnRender(); + draw.ProcessGPUTasks(); + + // Present image to screen in location of panel + m_pCore->GetRenderer()->AssignTextureTarget(0, 0); + + olc::vf2d vViewPos = { 0,0 }; + olc::vf2d vViewSize = { float(GetSize().x), float(GetSize().y) }; + + // Present final composite + m_pCore->GetRenderer()->SetViewport(vViewPos, vViewSize); + m_pCore->GetRenderer()->ClearViewport(olc::Colour::RED, true, true); + draw.SetBlendMode(olc::BlendMode::Alpha); + draw.SetCullMode(olc::CullMode::None); + draw.ImageRect(imgPrimary.flipV(), { 0.0,0.0 }, vViewSize); + draw.ProcessGPUTasks(); + + // Update Window's primary surface - via wxWidgets + SwapBuffers(); + } + + void PGE3Panel::Event_OnResize(wxSizeEvent& evt) + { + if (!bFixedSize) + { + // Resize Target Image + SetCurrent(*m_pCore->get()); + m_pCore->DestroyImage(imgPrimary); + m_pCore->CreateImage(imgPrimary, { evt.GetSize().x, evt.GetSize().y }); + } + + Refresh(true); + evt.Skip(true); + } + + olc::vf2d PGE3Panel::ScaleMouse(wxMouseEvent& evt) + { + olc::vf2d vScreenPos = olc::vf2d(float(evt.GetX()), float(evt.GetY())); + + if (bFixedSize) + vScreenPos = vScreenPos / olc::vf2d(GetSize().x, GetSize().y) * vFixedSizeImage; + + return vScreenPos; + } + + void PGE3Panel::Event_OnMouseLeftUp(wxMouseEvent& evt) + { + OnMouseLeftUp(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseLeftDown(wxMouseEvent& evt) + { + OnMouseLeftDown(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseRightUp(wxMouseEvent& evt) + { + OnMouseRightUp(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseRightDown(wxMouseEvent& evt) + { + OnMouseRightDown(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseMiddleUp(wxMouseEvent& evt) + { + OnMouseMiddleUp(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseMiddleDown(wxMouseEvent& evt) + { + OnMouseMiddleDown(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseMove(wxMouseEvent& evt) + { + OnMouseMove(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseWheel(wxMouseEvent& evt) + { + evt.Skip(); + } + +} +//! END IMPLEMENTATION diff --git a/dev/src/host_wxwidgets.h b/dev/src/host_wxwidgets.h new file mode 100644 index 0000000..16490ca --- /dev/null +++ b/dev/src/host_wxwidgets.h @@ -0,0 +1,118 @@ +#pragma once +#include "core.h" + +//! START STDHEADER GLOBAL +#include +#include +#include +//! END STDHEADER + +//! START CUSTOMHEADER +#include "pixel.h" +#include "vector2d.h" +#include "vector4d.h" +#include "matrix3d.h" +#include "matrix4d.h" +#include "transform2d.h" +#include "image.h" +#include "imload_iface.h" +#include "gpu_iface.h" +//! END CUSTOMHEADER + +//! START WXWIDGETS_CONFIG +#include +#include +//! END WXWIDGETS_CONFIG + +//! START DECLARATION +// Not really an olc::Host, but some stand alone components that wxWidgets +// can use and get a PGE3 like rendering and user experience +namespace olc::wx +{ + class PGE3Core : public wxGLCanvas + { + public: + PGE3Core(wxWindow* parent); + virtual ~PGE3Core(); + + // Create an image resource + bool CreateImage(olc::Image& image, const olc::vi2d& size, const ImageConfig& cfg = olc::ImageConfig()); + // Create an image resource based on an image file asset on disk + bool CreateImageFromFile(olc::Image& image, const std::string& sFileName, const ImageConfig& cfg = olc::ImageConfig()); + // 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, const ImageConfig& cfg = olc::ImageConfig()); + // 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); + // Destroy an image + void DestroyImage(olc::Image& image); + + public: + wxGLContext* get() const; + olc::gpu::Renderer* GetRenderer(); + olc::imload::ImageLoader* GetImageLoader(); + + private: // wxWidgets Specific + wxGLContext* m_glContext = nullptr; + + private: // Global PGE3 Components (excluding host) + std::unique_ptr pRenderer; + std::unique_ptr pImageLoader; + }; + + class PGE3Panel : public wxGLCanvas + { + public: + PGE3Panel(wxWindow* parent); + PGE3Panel(wxWindow* parent, const olc::vi2d& vFixedSize); + virtual ~PGE3Panel(); + + void ResetDrawState(); + + protected: // Local PGE3 Components + olc::Draw draw; + + private: + // Same core is loaded across all panels in application + static olc::wx::PGE3Core* m_pCore; + olc::Image imgPrimary; + + bool bFixedSize = false; + olc::vi2d vFixedSizeImage; + + olc::vf2d ScaleMouse(wxMouseEvent& evt); + + + private: // wxWidgets Overrides + void Event_OnPaint(wxPaintEvent& evt); + void Event_OnResize(wxSizeEvent& evt); + void Event_OnMouseLeftUp(wxMouseEvent& evt); + void Event_OnMouseLeftDown(wxMouseEvent& evt); + void Event_OnMouseRightUp(wxMouseEvent& evt); + void Event_OnMouseRightDown(wxMouseEvent& evt); + void Event_OnMouseMiddleUp(wxMouseEvent& evt); + void Event_OnMouseMiddleDown(wxMouseEvent& evt); + void Event_OnMouseMove(wxMouseEvent& evt); + void Event_OnMouseWheel(wxMouseEvent& evt); + + + protected: // User Overrides + virtual void OnRender() {}; // Called via wxWidgets ->Refresh() + + public: + virtual void OnCreate() {}; + virtual void OnUpdate(const float fElapsedTime) {}; + + // Mouse Handlers + virtual void OnMouseMiddleUp(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseMiddleDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseLeftUp(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseLeftDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseRightUp(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseRightDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseMove(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseWheel(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + }; +} +//! END DECLARATION diff --git a/dev/src/image.cpp b/dev/src/image.cpp index beadcc5..4c48037 100644 --- a/dev/src/image.cpp +++ b/dev/src/image.cpp @@ -3,19 +3,13 @@ //! START IMPLEMENTATION namespace olc { - /*Image::Image(const olc::vi2d& size, const ImageConfig& cfg) - { - } - - Image::~Image() - { - }*/ bool Image::CreateNoGPU(const olc::vi2d& size, const ImageConfig& cfg) { dimensions = size; config = cfg; pixels.resize(dimensions.area(), olc::Colour::TANGERINE); + BindCPU(); return true; } @@ -78,6 +72,11 @@ namespace olc return onCPU; } + olc::ImageRegion Image::all() + { + return olc::ImageRegion(*this); + } + 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); diff --git a/dev/src/image.h b/dev/src/image.h index cab7215..6cd93c2 100644 --- a/dev/src/image.h +++ b/dev/src/image.h @@ -45,6 +45,12 @@ namespace olc Image() = default; virtual ~Image() = default; + // Prevent copying & accidental duplication + Image(const Image&) = delete; + Image& operator=(const Image&) = delete; + Image(Image&&) = default; + Image& operator=(Image&&) = default; + public: // Creates nothing but an array of pixels in system memory. Normal users // should never need to call this method. If you want to construct an @@ -77,6 +83,7 @@ namespace olc bool BoundToCPU() const; public: + olc::ImageRegion all(); 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); olc::ImageRegion flipV(); diff --git a/dev/src/sh_template.h b/dev/src/sh_template.h index 2176722..c17379f 100644 --- a/dev/src/sh_template.h +++ b/dev/src/sh_template.h @@ -93,6 +93,11 @@ "You know you don't have to use AI if you like coding right?" - javidx9 + Identified Uses of AI + ~~~~~~~~~~~~~~~~~~~~~ + 1) NxN Matrix Inversion - After 4 attempts at getting the sequencing right following + the wikipedia articles (VS Copilot) + Primary Contributors ~~~~~~~~~~~~~~~~~~~~ @javidx9 (aka David Barr, OneLoneCoder) @@ -147,6 +152,7 @@ //! GRAB hw_touch.h DECLARATION +#if OLC_HOST != OLC_HOST_WXWIDGETS //! GRAB window.h DECLARATION //! GRAB host_iface.h DECLARATION @@ -154,14 +160,14 @@ //! GRAB extension.h DECLARATION //! GRAB core.h DECLARATION +#endif - - +#if !defined(OLC_USE_WXWIDGETS) #if OLC_HOST == OLC_HOST_NONE //! GRAB host_none.h NOHOST_CONFIG @@ -209,6 +215,13 @@ //! GRAB host_android.h DECLARATION #endif +#else +//! GRAB host_wxwidgets.h WXWIDGETS_CONFIG + +//! GRAB host_wxwidgets.h DECLARATION +#endif + + #if OLC_GPU == OLC_GPU_NONE //! GRAB gpu_none.h DECLARATION #endif @@ -246,6 +259,9 @@ #if defined(OLC_PGE3_APPLICATION) && !defined(PGE_HOST_IMPLEMENTED) + +#if !defined(OLC_USE_WXWIDGETS) + #if OLC_HOST == OLC_HOST_NONE //! GRAB host_none.cpp IMPLEMENTATION #endif @@ -253,11 +269,11 @@ #if OLC_HOST == OLC_HOST_WINDOWS //! GRAB host_win_winapi.cpp IMPLEMENTATION #endif + #if OLC_HOST == OLC_HOST_MACOS //! GRAB host_apple_macos.cpp IMPLEMENTATION //! GRAB api_macos.cpp IMPLEMENTATION - #endif #if OLC_HOST == OLC_HOST_LINUX_X11 @@ -276,6 +292,10 @@ //! GRAB host_android.cpp IMPLEMENTATION #endif +#else // Using wxWidgets +//! GRAB host_wxwidgets.cpp IMPLEMENTATION +#endif + #define PGE_HOST_IMPLEMENTED 1 #endif @@ -300,7 +320,7 @@ #define PGE_DRAW_IMPLEMENTED 1 #endif -#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_CORE_IMPLEMENTED) +#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_CORE_IMPLEMENTED) && !defined(OLC_USE_WXWIDGETS) //! GRAB core.cpp IMPLEMENTATION #define PGE_CORE_IMPLEMENTED 1 #endif @@ -330,7 +350,7 @@ #define PGE_HW_TOUCH_IMPLEMENTED 1 #endif -#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) +#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) && !defined(OLC_USE_WXWIDGETS) //! GRAB window.cpp IMPLEMENTATION #define PGE_WINDOW_IMPLEMENTED 1 #endif diff --git a/extensions/README.md b/extensions/README.md new file mode 100644 index 0000000..6ae8e9f --- /dev/null +++ b/extensions/README.md @@ -0,0 +1,14 @@ +# Extensions +In PGE3, an extension allows the easy addition of automated functionality or wrapping of 3rd party libraries. Extensions **ADD** features by hooking into the main system loop and being called by PGE3 at various points. + +Extensions live in the `olc::ext` namespace. + +For example, the SplashScreen extension simply requires the presence of an `olc::ext::SplashScreen` object, and PGE3 will take care of the sequencing and rendering, removing that burden from the user. More complicated extensions such as audio may comprise several files or indeed require the installation of additional libraries. + +Extension code should exist in a self-contained and self-named folder, along with a `README.md` detailing their use and installation requirements. No 3rd party code should be stored within the folder, and we expect the README to sufficiently inform the user how to acquire, configure and use any 3rd part libraries. + +Support for extensions is not guaranteed, as extension maintainers come and go, 3rd party libraries change over time and the requirements for the extension may disappear. + +If you have an extension idea or contribution, then please reach out via our Discord server. + +`TODO: Basic Extension Writing Guide` \ No newline at end of file diff --git a/extensions/miniaudio/README.md b/extensions/miniaudio/README.md new file mode 100644 index 0000000..e69de29 diff --git a/extensions/splashscreen/README.md b/extensions/splashscreen/README.md new file mode 100644 index 0000000..e69de29 diff --git a/olcPixelGameEngine3.h b/olcPixelGameEngine3.h index a8a4da8..c239002 100644 --- a/olcPixelGameEngine3.h +++ b/olcPixelGameEngine3.h @@ -93,6 +93,11 @@ "You know you don't have to use AI if you like coding right?" - javidx9 + Identified Uses of AI + ~~~~~~~~~~~~~~~~~~~~~ + 1) NxN Matrix Inversion - After 4 attempts at getting the sequencing right following + the wikipedia articles (VS Copilot) + Primary Contributors ~~~~~~~~~~~~~~~~~~~~ @javidx9 (aka David Barr, OneLoneCoder) @@ -175,6 +180,7 @@ #define OLC_HOST_ANDROID 7 #define OLC_HOST_IOS 8 + #if !defined(OLC_HOST) #if defined(_WIN32) #define OLC_HOST OLC_HOST_WINDOWS @@ -263,6 +269,7 @@ #define OLC_IMAGELOADER OLC_IMAGELOADER_NDK_IMAGEDECODER #define OLC_IMAGELOADER_CLASS ImageLoader_NDKImageDecoder #endif + #endif // We wait until after the platform specific image loader is selected @@ -340,6 +347,7 @@ inline constexpr void olc_IgnoreUnused(Args&&...) noexcept {} #endif + #if !defined(PGE_PIXEL_DECLARED) #if OLC_HOST == OLC_HOST_MACOS #pragma clang diagnostic push @@ -2267,6 +2275,12 @@ namespace olc Image() = default; virtual ~Image() = default; + // Prevent copying & accidental duplication + Image(const Image&) = delete; + Image& operator=(const Image&) = delete; + Image(Image&&) = default; + Image& operator=(Image&&) = default; + public: // Creates nothing but an array of pixels in system memory. Normal users // should never need to call this method. If you want to construct an @@ -2299,6 +2313,7 @@ namespace olc bool BoundToCPU() const; public: + olc::ImageRegion all(); 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); olc::ImageRegion flipV(); @@ -2414,7 +2429,15 @@ namespace olc #if !defined(PGE_FONT_DECLARED) namespace olc { +#if defined(OLC_USE_WXWIDGETS) + namespace wx + { + class PGE3Core; + } +#else class PGEWindow; +#endif + struct FontGlyph { @@ -2457,7 +2480,11 @@ namespace olc namespace pgeguts { // Create the classic PGE font +#if defined(OLC_USE_WXWIDGETS) + void CreateClassicFont(olc::wx::PGE3Core* pge); +#else void CreateClassicFont(olc::PGEWindow* pge); +#endif } } @@ -3872,6 +3899,7 @@ namespace olc #define PGE_HW_TOUCH_DECLARED 1 #endif +#if OLC_HOST != OLC_HOST_WXWIDGETS #if !defined(PGE_WINDOW_DECLARED) namespace olc { @@ -4361,14 +4389,14 @@ namespace olc } #define PGE_CORE_DECLARED 1 #endif +#endif - - +#if !defined(OLC_USE_WXWIDGETS) #if OLC_HOST == OLC_HOST_NONE @@ -6617,6 +6645,103 @@ namespace olc::host } #endif +#else +#include +#include + +// Not really an olc::Host, but some stand alone components that wxWidgets +// can use and get a PGE3 like rendering and user experience +namespace olc::wx +{ + class PGE3Core : public wxGLCanvas + { + public: + PGE3Core(wxWindow* parent); + virtual ~PGE3Core(); + + // Create an image resource + bool CreateImage(olc::Image& image, const olc::vi2d& size, const ImageConfig& cfg = olc::ImageConfig()); + // Create an image resource based on an image file asset on disk + bool CreateImageFromFile(olc::Image& image, const std::string& sFileName, const ImageConfig& cfg = olc::ImageConfig()); + // 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, const ImageConfig& cfg = olc::ImageConfig()); + // 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); + // Destroy an image + void DestroyImage(olc::Image& image); + + public: + wxGLContext* get() const; + olc::gpu::Renderer* GetRenderer(); + olc::imload::ImageLoader* GetImageLoader(); + + private: // wxWidgets Specific + wxGLContext* m_glContext = nullptr; + + private: // Global PGE3 Components (excluding host) + std::unique_ptr pRenderer; + std::unique_ptr pImageLoader; + }; + + class PGE3Panel : public wxGLCanvas + { + public: + PGE3Panel(wxWindow* parent); + PGE3Panel(wxWindow* parent, const olc::vi2d& vFixedSize); + virtual ~PGE3Panel(); + + void ResetDrawState(); + + protected: // Local PGE3 Components + olc::Draw draw; + + private: + // Same core is loaded across all panels in application + static olc::wx::PGE3Core* m_pCore; + olc::Image imgPrimary; + + bool bFixedSize = false; + olc::vi2d vFixedSizeImage; + + olc::vf2d ScaleMouse(wxMouseEvent& evt); + + + private: // wxWidgets Overrides + void Event_OnPaint(wxPaintEvent& evt); + void Event_OnResize(wxSizeEvent& evt); + void Event_OnMouseLeftUp(wxMouseEvent& evt); + void Event_OnMouseLeftDown(wxMouseEvent& evt); + void Event_OnMouseRightUp(wxMouseEvent& evt); + void Event_OnMouseRightDown(wxMouseEvent& evt); + void Event_OnMouseMiddleUp(wxMouseEvent& evt); + void Event_OnMouseMiddleDown(wxMouseEvent& evt); + void Event_OnMouseMove(wxMouseEvent& evt); + void Event_OnMouseWheel(wxMouseEvent& evt); + + + protected: // User Overrides + virtual void OnRender() {}; // Called via wxWidgets ->Refresh() + + public: + virtual void OnCreate() {}; + virtual void OnUpdate(const float fElapsedTime) {}; + + // Mouse Handlers + virtual void OnMouseMiddleUp(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseMiddleDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseLeftUp(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseLeftDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseRightUp(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseRightDown(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseMove(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + virtual void OnMouseWheel(const olc::vf2d& vWorldPos, const bool bShift, const bool bControl) {}; + }; +} +#endif + + #if OLC_GPU == OLC_GPU_NONE #if !defined(PGE_RENDERER_NONE_DECLARED) @@ -6764,6 +6889,11 @@ namespace olc::gpu #define OGL_LOAD(t) reinterpret_cast(eglGetProcAddress(#t)) #endif +#if OLC_HOST == OLC_HOST_WXWIDGETS + + +#endif + #if !defined(CALLSTYLE) #define CALLSTYLE #endif @@ -7346,6 +7476,9 @@ namespace olc::imload #if defined(OLC_PGE3_APPLICATION) && !defined(PGE_HOST_IMPLEMENTED) + +#if !defined(OLC_USE_WXWIDGETS) + #if OLC_HOST == OLC_HOST_NONE namespace olc::host { @@ -8310,6 +8443,7 @@ namespace olc::host }; #endif + #if OLC_HOST == OLC_HOST_MACOS namespace olc::host { @@ -12074,7 +12208,6 @@ extern "C" { } // extern "C" - #endif #if OLC_HOST == OLC_HOST_LINUX_X11 @@ -15288,6 +15421,336 @@ void android_main(struct android_app* app) } #endif +#else // Using wxWidgets +namespace olc::wx +{ + PGE3Core::PGE3Core(wxWindow* parent) : wxGLCanvas(parent, -1, nullptr) + { + // Create a wxWidgets "glContext" targeting OpenGL 3.3 + wxGLContextAttrs ctxAttrs; + ctxAttrs.CoreProfile().OGLVersion(3, 3).EndList(); + m_glContext = new wxGLContext(this, NULL, &ctxAttrs); + SetCurrent(*m_glContext); + + + // Create all the vital parts of PGE + pImageLoader = std::make_unique(); + + // Create the renderer + olc::gpu::RendererConfig cfgRenderer; + pRenderer = std::make_unique(); + pRenderer->CreateDevice({ this }, cfgRenderer); + + // Load the font + olc::pgeguts::CreateClassicFont(this); + + // wxWidgets should hide this pseudo-canvas. It was only + // needed to get the context + this->Hide(); + } + + PGE3Core::~PGE3Core() + { + delete m_glContext; + } + + bool PGE3Core::CreateImage(olc::Image& image, const olc::vi2d& size, const ImageConfig& cfg) + { + // Create CPU Image + if (!image.CreateNoGPU(size, cfg)) + return false; + + // Create GPU Image + auto id = pRenderer->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.CreateNoGPU({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + + bool PGE3Core::CreateImageFromFile(olc::Image& image, const std::string& sFileName, const ImageConfig& cfg) + { + if (pImageLoader->CreateImageFromFile(image, sFileName)) + { + // Image has loaded ok, and populated into pixel vector + // + // Create GPU Image + auto id = pRenderer->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.CreateNoGPU({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + + return false; + } + + bool PGE3Core::CreateImageFromMemory(olc::Image& image, const uint8_t* data, const size_t bytes, const ImageConfig& cfg) + { + if (pImageLoader->CreateImageFromMemory(image, data, bytes)) + { + // Image has loaded ok, and populated into pixel vector + // + // Create GPU Image + auto id = pRenderer->CreateTexture(image.Size(), cfg); + if (id == 0) + { + image.CreateNoGPU({ 0,0 }); + return false; + } + + // Associate CPU object with GPU Resource + image.SetGPUID(id); + return true; + } + + std::cout << "Create From Memory Failed\n"; + return false; + } + + bool PGE3Core::WriteImageToFile(const olc::Image& image, const std::string& sFileName) + { + olc_IgnoreUnused(image, sFileName); + return false; + } + + void PGE3Core::DestroyImage(olc::Image& image) + { + // If image has gpu resource, remove it + if (image.GetGPUID() != 0) + { + pRenderer->DeleteTexture(uint32_t(image.GetGPUID())); + image.SetGPUID(0); + } + + // Free any cpu memory associated with image + image.CreateNoGPU({ 0,0 }); + } + + wxGLContext* PGE3Core::get() const + { + return m_glContext; + } + + olc::gpu::Renderer* PGE3Core::GetRenderer() + { + return pRenderer.get(); + } + + olc::imload::ImageLoader* PGE3Core::GetImageLoader() + { + return pImageLoader.get(); + } + + + + olc::wx::PGE3Core* PGE3Panel::m_pCore = nullptr; + + + + PGE3Panel::PGE3Panel(wxWindow* parent) : wxGLCanvas(parent, -1, nullptr) + { + if (m_pCore == nullptr) + { + // Create a static PGE3Core + m_pCore = new PGE3Core(this); + } + + // Set the context via wxWidgets + SetCurrent(*m_pCore->get()); + + // Associate this instance of draw with the renderer + draw.SetGPU(m_pCore->GetRenderer()); + + // Create the default draw target + bFixedSize = false; + m_pCore->CreateImage(imgPrimary, { 256, 240 }); + + ResetDrawState(); + + Connect(wxEVT_PAINT, wxPaintEventHandler(olc::wx::PGE3Panel::Event_OnPaint)); + Connect(wxEVT_SIZE, wxSizeEventHandler(olc::wx::PGE3Panel::Event_OnResize)); + Connect(wxEVT_MOTION, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMove)); + Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleDown)); + Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleUp)); + Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseWheel)); + Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftDown)); + Connect(wxEVT_LEFT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftUp)); + Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightDown)); + Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightUp)); + } + + PGE3Panel::PGE3Panel(wxWindow* parent, const olc::vi2d& vFixedSize) : wxGLCanvas(parent, -1, nullptr) + { + if (m_pCore == nullptr) + { + // Create a static PGE3Core + m_pCore = new PGE3Core(this); + } + + // Set the context via wxWidgets + SetCurrent(*m_pCore->get()); + + // Associate this instance of draw with the renderer + draw.SetGPU(m_pCore->GetRenderer()); + + // Create the default draw target + vFixedSizeImage = vFixedSize; + bFixedSize = true; + m_pCore->CreateImage(imgPrimary, vFixedSize); + + ResetDrawState(); + + Connect(wxEVT_PAINT, wxPaintEventHandler(olc::wx::PGE3Panel::Event_OnPaint)); + Connect(wxEVT_MOTION, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMove)); + Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleDown)); + Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleUp)); + Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseWheel)); + Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftDown)); + Connect(wxEVT_LEFT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftUp)); + Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightDown)); + Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightUp)); + } + + PGE3Panel::~PGE3Panel() + { + Disconnect(wxEVT_PAINT, wxPaintEventHandler(olc::wx::PGE3Panel::Event_OnPaint)); + Disconnect(wxEVT_SIZE, wxSizeEventHandler(olc::wx::PGE3Panel::Event_OnResize)); + Disconnect(wxEVT_MOTION, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMove)); + Disconnect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleDown)); + Disconnect(wxEVT_MIDDLE_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseMiddleUp)); + Disconnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseWheel)); + Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftDown)); + Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseLeftUp)); + Disconnect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightDown)); + Disconnect(wxEVT_RIGHT_UP, wxMouseEventHandler(olc::wx::PGE3Panel::Event_OnMouseRightUp)); + } + + void PGE3Panel::ResetDrawState() + { + // Set the context via wxWidgets + SetCurrent(*m_pCore->get()); + m_pCore->GetRenderer()->ApplyDefaultShader(); + draw.SetTarget(imgPrimary); + draw.WorldReset(); + draw.SetBlendMode(olc::BlendMode::Alpha); + draw.SetCullMode(olc::CullMode::None); + } + + + + void PGE3Panel::Event_OnPaint(wxPaintEvent& evt) + { + // Configure WX to render this window + wxPaintDC(this); + + // Perform actual render + ResetDrawState(); + OnRender(); + draw.ProcessGPUTasks(); + + // Present image to screen in location of panel + m_pCore->GetRenderer()->AssignTextureTarget(0, 0); + + olc::vf2d vViewPos = { 0,0 }; + olc::vf2d vViewSize = { float(GetSize().x), float(GetSize().y) }; + + // Present final composite + m_pCore->GetRenderer()->SetViewport(vViewPos, vViewSize); + m_pCore->GetRenderer()->ClearViewport(olc::Colour::RED, true, true); + draw.SetBlendMode(olc::BlendMode::Alpha); + draw.SetCullMode(olc::CullMode::None); + draw.ImageRect(imgPrimary.flipV(), { 0.0,0.0 }, vViewSize); + draw.ProcessGPUTasks(); + + // Update Window's primary surface - via wxWidgets + SwapBuffers(); + } + + void PGE3Panel::Event_OnResize(wxSizeEvent& evt) + { + if (!bFixedSize) + { + // Resize Target Image + SetCurrent(*m_pCore->get()); + m_pCore->DestroyImage(imgPrimary); + m_pCore->CreateImage(imgPrimary, { evt.GetSize().x, evt.GetSize().y }); + } + + Refresh(true); + evt.Skip(true); + } + + olc::vf2d PGE3Panel::ScaleMouse(wxMouseEvent& evt) + { + olc::vf2d vScreenPos = olc::vf2d(float(evt.GetX()), float(evt.GetY())); + + if (bFixedSize) + vScreenPos = vScreenPos / olc::vf2d(GetSize().x, GetSize().y) * vFixedSizeImage; + + return vScreenPos; + } + + void PGE3Panel::Event_OnMouseLeftUp(wxMouseEvent& evt) + { + OnMouseLeftUp(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseLeftDown(wxMouseEvent& evt) + { + OnMouseLeftDown(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseRightUp(wxMouseEvent& evt) + { + OnMouseRightUp(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseRightDown(wxMouseEvent& evt) + { + OnMouseRightDown(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseMiddleUp(wxMouseEvent& evt) + { + OnMouseMiddleUp(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseMiddleDown(wxMouseEvent& evt) + { + OnMouseMiddleDown(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseMove(wxMouseEvent& evt) + { + OnMouseMove(draw.ScreenToWorld(ScaleMouse(evt)), evt.ShiftDown(), evt.ControlDown()); + evt.Skip(); + } + + void PGE3Panel::Event_OnMouseWheel(wxMouseEvent& evt) + { + evt.Skip(); + } + +} +#endif + #define PGE_HOST_IMPLEMENTED 1 #endif @@ -16280,7 +16743,8 @@ void main() config = cfg; - +#if !defined(OLC_USE_WXWIDGETS) + #if OLC_HOST == OLC_HOST_WINDOWS // Create OpenGL Device Context if (!PrepareWindowTarget(os_win_id)) @@ -16413,6 +16877,10 @@ void main() } #endif +#else // wxWidgets specific + +#endif // wxWidgets + // Can't load OpenGL API until context is loaded auto& gl = olc::apis::opengl::gl::Get(); if (!gl.HasLoaded()) @@ -16823,6 +17291,14 @@ void main() gl.glDeleteRenderbuffers(1, &rboId); mapTextureToRenderbuffer.erase(texid); } + + mapTextureSizes.erase(texid); + + if (nCurrentTextureSource == texid) + nCurrentTextureSource = 0; + + if (nCurrentTextureTarget == texid) + nCurrentTextureTarget = 0; return true; } @@ -19240,7 +19716,7 @@ const ImageBatch& olc::Draw::ImageRect(olc::ImageBatch& batch, olc::ImageRegion #define PGE_DRAW_IMPLEMENTED 1 #endif -#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_CORE_IMPLEMENTED) +#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_CORE_IMPLEMENTED) && !defined(OLC_USE_WXWIDGETS) namespace olc { PGEWindow::PGEWindow() : Window(), draw() @@ -19894,19 +20370,13 @@ namespace olc #if defined(OLC_PGE3_APPLICATION) && !defined(PGE_IMAGE_IMPLEMENTED) namespace olc { - /*Image::Image(const olc::vi2d& size, const ImageConfig& cfg) - { - } - - Image::~Image() - { - }*/ bool Image::CreateNoGPU(const olc::vi2d& size, const ImageConfig& cfg) { dimensions = size; config = cfg; pixels.resize(dimensions.area(), olc::Colour::TANGERINE); + BindCPU(); return true; } @@ -19969,6 +20439,11 @@ namespace olc return onCPU; } + olc::ImageRegion Image::all() + { + return olc::ImageRegion(*this); + } + 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); @@ -20012,7 +20487,11 @@ namespace olc { namespace pgeguts { +#if defined(OLC_USE_WXWIDGETS) + void CreateClassicFont(olc::wx::PGE3Core* pge) +#else void CreateClassicFont(olc::PGEWindow* pge) +#endif { std::string data = "?Q`0001oOch0o01o@F40o000000000" @@ -20472,7 +20951,7 @@ namespace olc::hw #define PGE_HW_TOUCH_IMPLEMENTED 1 #endif -#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) +#if defined(OLC_PGE3_APPLICATION) && !defined(PGE_WINDOW_IMPLEMENTED) && !defined(OLC_USE_WXWIDGETS) namespace olc { Window::Window() diff --git a/utilities/README.md b/utilities/README.md new file mode 100644 index 0000000..13def36 --- /dev/null +++ b/utilities/README.md @@ -0,0 +1,6 @@ +# Utilities +A Utility in PGE3 is a single header file, assistive set of data structures, classes and algorithms intended to simplify common procedures. For example, the Camera2D utility will transform a game world to the screen in various ways, and the QuadTree can partition 2D space for efficient search or rendering. + +The core PGE3 doesn't rely upon utilities meaning they are entirely optional, however utilities and extensions may rely upon other utilities. + +Documentation for a utility if not obvious, should be included within the utility file itself. \ No newline at end of file