diff --git a/CMakeLists.txt b/CMakeLists.txt index cc0bfb7..8e30baa 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,110 +14,115 @@ option(PD_BUILD_SHARED "Build Shared Library" OFF) option(PD_BUILD_TOOLS "Build Palladium Tools" OFF) if(${PD_BUILD_TOOLS}) - add_subdirectory(tools) + add_subdirectory(tools) endif() add_subdirectory(vendor) # # Include Library Source set(PD_SOURCES - # Common - source/common.cpp + # Common + source/common.cpp - # Core - source/core/bits.cpp - source/core/color.cpp - source/core/mat.cpp - source/core/strings.cpp + # Core + source/core/bits.cpp + source/core/color.cpp + source/core/mat.cpp + source/core/strings.cpp - # Drivers - source/drivers/os.cpp - source/drivers/gfx.cpp + # Drivers + source/drivers/os.cpp + source/drivers/gfx.cpp - # Lithium - source/lithium/pools.cpp + # Lithium + source/lithium/pools.cpp ) if(${PD_BUILD_SHARED}) - add_library(palladium SHARED ${PD_SOURCES}) - target_compile_definitions(palladium PRIVATE -DPD_BUILD_SHARED) + add_library(palladium SHARED ${PD_SOURCES}) + target_compile_definitions(palladium PRIVATE PD_BUILD_SHARED) else() - add_library(palladium STATIC ${PD_SOURCES}) - target_compile_definitions(palladium PUBLIC -DPD_BUILD_STATIC) + add_library(palladium STATIC ${PD_SOURCES}) + target_compile_definitions(palladium PUBLIC PD_BUILD_STATIC) endif() -target_compile_definitions(palladium PUBLIC -DPD_DEBUG=1) +target_compile_definitions(palladium PUBLIC PD_DEBUG) target_compile_options(palladium - PUBLIC - -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/source=source - -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/include=include + PUBLIC + $<$: + -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/source=source + -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/include=include + > ) add_library(palladium::palladium ALIAS palladium) target_include_directories(palladium - PUBLIC - $ - $ + PUBLIC + $ + $ ) target_compile_options(palladium - PRIVATE - $<$:-O0 -g> - $<$:-O3> + PRIVATE + $<$,$>:-O0 -g> + $<$,$>:-O3> + + $<$,$>:/Od /Zi> + $<$,$>:/O2> ) install( - TARGETS palladium - EXPORT palladiumTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + TARGETS palladium + EXPORT palladiumTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install( - DIRECTORY include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) install(EXPORT palladiumTargets - FILE palladiumTargets.cmake - NAMESPACE palladium:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/palladium + FILE palladiumTargets.cmake + NAMESPACE palladium:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/palladium ) include(CMakePackageConfigHelpers) configure_package_config_file( - cmake/palladiumConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfig.cmake - INSTALL_DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/palladium + cmake/palladiumConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfig.cmake + INSTALL_DESTINATION + ${CMAKE_INSTALL_LIBDIR}/cmake/palladium ) write_basic_package_version_file( - ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfigVersion.cmake - VERSION - ${PROJECT_VERSION} - COMPATIBILITY - SameMajorVersion + ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfigVersion.cmake + VERSION + ${PROJECT_VERSION} + COMPATIBILITY + SameMajorVersion ) install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/palladium + FILES + ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/palladiumConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/palladium ) find_program(CLANG_FORMAT clang-format) file(GLOB_RECURSE PD_FMTFILES - CONFIGURE_DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp ) add_custom_target(pd-clang-format - COMMAND ${CLANG_FORMAT} --style=file -i ${PD_FMTFILES} - COMMENT "Formatting Project Sources" + COMMAND ${CLANG_FORMAT} --style=file -i ${PD_FMTFILES} + COMMENT "Formatting Project Sources" ) add_subdirectory(backends) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index f0e7d6e..a23c9a7 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -4,26 +4,60 @@ project(pd-system) option(PD_ENABLE_OPENGL2 "Enable OpenGL 2.1 (On Supported Hardware)" ON) option(PD_ENABLE_OPENGL3 "Enable OpenGL 3.3 (On Supported Hardware)" ON) +option(PD_ENABLE_DIRECTX9 "Enable DirectX9 Support" ON) +option(PD_ENABLE_CITRO3D "Enable Citro3D Support (3DS)" OFF) option(PD_ENABLE_VULKAN "Not implemented yet" OFF) +if(NOT WIN32) # cause we are not on windows... + set(PD_ENABLE_DIRECTX9 OFF) +endif() + add_library(pd-system STATIC - ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/gl-helper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_opengl3.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_directx9.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/source/gfx_citro3d.cpp ) target_include_directories(pd-system - PUBLIC - $ - $ + PUBLIC + $ + $ ) -target_compile_options(pd-system - PUBLIC - -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/source=source - -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/include=include +target_compile_options(palladium + PUBLIC + $<$: + -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/source=source + -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/include=include + > ) -target_link_libraries(pd-system - PUBLIC - palladium::palladium - glad -) \ No newline at end of file +target_compile_definitions(pd-system + PUBLIC + $<$:PD_ENABLE_OPENGL2> + $<$:PD_ENABLE_OPENGL3> + $<$:PD_ENABLE_VULKAN> + $<$:PD_ENABLE_DIRECTX9> +) + +# Palladium +target_link_libraries(pd-system PUBLIC palladium::palladium) + +# glad (if we have any OpenGL version included) +if(PD_ENABLE_OPENGL2 OR PD_ENABLE_OPENGL3) + target_link_libraries(pd-system + PUBLIC + glad + ) +endif() + +# DirectX9 +if(PD_ENABLE_DIRECTX9) + target_link_libraries(pd-system + PUBLIC + d3d9 + d3dcompiler + ) +endif() diff --git a/backends/include/pd_system/ctr-linear-allocator.hpp b/backends/include/pd_system/ctr-linear-allocator.hpp new file mode 100644 index 0000000..c043993 --- /dev/null +++ b/backends/include/pd_system/ctr-linear-allocator.hpp @@ -0,0 +1,67 @@ +#pragma once + +#ifdef __3DS__ +#include <3ds.h> +#endif + +#include +#include +#include + +// Custom C++ Allocator class to interface with libctru linear heap memory +// based on this guide: +// https://johnfarrier.com/custom-allocators-in-c-high-performance-memory-management/ + +namespace PD { +template +class LinearAllocator { + public: + using value_type = T; + LinearAllocator() noexcept = default; + template + constexpr LinearAllocator(const LinearAllocator&) noexcept {} + + T* allocate(std::size_t n) { + if (n > max_size()) { + throw std::runtime_error("[PD] LinearAllocator: Bad alloc!"); + } +#ifdef __3DS__ + return static_cast(linearAlloc(n * sizeof(T))); +#else + return static_cast(malloc(n * sizeof(T))); +#endif + } +#ifdef __3DS__ + void deallocate(T* p, std::size_t) noexcept { linearFree(p); } +#else + void deallocate(T* p, std::size_t) noexcept { free(p); } +#endif + + template + void construct(U* p, Args&&... args) { + ::new ((void*)p) U(std::forward(args)...); + } + + template + void destroy(U* p) { + p->~U(); + } + + friend bool operator==(const LinearAllocator, const LinearAllocator) { + return true; + } + friend bool operator!=(const LinearAllocator, const LinearAllocator) { + return false; + } + +#ifdef __3DS__ + // Use linearSpace free as max_size to not allocate out of bounds + // or to b eable to see a crash report screen. + size_t max_size() const noexcept { return linearSpaceFree(); } +#else + size_t max_size() const noexcept { + return std::numeric_limits::max(); + } +#endif +}; +} // namespace PD \ No newline at end of file diff --git a/backends/include/pd_system/gfx_citro3d.hpp b/backends/include/pd_system/gfx_citro3d.hpp new file mode 100644 index 0000000..122ace8 --- /dev/null +++ b/backends/include/pd_system/gfx_citro3d.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +namespace PD { +struct GfxCitro3DConfig { + // Vertex Allocator + template + using VertexAlloc = LinearAllocator; + // Index Allocator + template + using IndexAlloc = LinearAllocator; + + static constexpr size_t NumVertices = 32768; // 8192*4 + static constexpr size_t NumIndices = 49152; // 8192*6 +}; + +class GfxCitro3D : public GfxDriverBase { + public: + GfxCitro3D() : GfxDriverBase("Citro3D") {} + ~GfxCitro3D() {} + + void SysInit() override; + void SysDeinit() override; + void Submit(size_t count, size_t start) override; + void BindTexture(TextureID id) override; + void SysReset() override; + TextureID LoadTexture(const std::vector& pixels, int w, int h, + TextureFormat type = TextureFormat::RGBA32, + TextureFilter filter = TextureFilter::Linear) override; + void DeleteTexture(const TextureID& tex) override; + + private: + struct Impl; + Impl* impl = nullptr; +}; +} // namespace PD \ No newline at end of file diff --git a/backends/include/pd_system/gfx_directx9.hpp b/backends/include/pd_system/gfx_directx9.hpp new file mode 100644 index 0000000..9d50dd3 --- /dev/null +++ b/backends/include/pd_system/gfx_directx9.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace PD { +struct GfxDirectX9Config { + // Vertex Allocator + template + using VertexAlloc = std::allocator; + // Index Allocator + template + using IndexAlloc = std::allocator; + + static constexpr size_t NumVertices = 32768; // 8192*4 + static constexpr size_t NumIndices = 49152; // 8192*6 +}; + +class GfxDirectX9 : public GfxDriverBase { + public: + GfxDirectX9(void* device = nullptr) + : GfxDriverBase("DirectX9"), pDevice(device) {} + ~GfxDirectX9() {} + + void SysInit() override; + void SysDeinit() override; + void Submit(size_t count, size_t start) override; + void BindTexture(TextureID id) override; + void SysReset() override; + TextureID LoadTexture(const std::vector& pixels, int w, int h, + TextureFormat type = TextureFormat::RGBA32, + TextureFilter filter = TextureFilter::Linear) override; + void DeleteTexture(const TextureID& tex) override; + + private: + struct Impl; + Impl* impl = nullptr; + void* pDevice = nullptr; +}; +} // namespace PD \ No newline at end of file diff --git a/backends/include/gfx_opengl.hpp b/backends/include/pd_system/gfx_opengl2.hpp similarity index 82% rename from backends/include/gfx_opengl.hpp rename to backends/include/pd_system/gfx_opengl2.hpp index 4b48698..e53c7f9 100644 --- a/backends/include/gfx_opengl.hpp +++ b/backends/include/pd_system/gfx_opengl2.hpp @@ -3,22 +3,22 @@ #include namespace PD { -struct GfxOpenGLConfig { +struct GfxOpenGL2Config { // Vertex Allocator template using VertexAlloc = std::allocator; // Index Allocator template using IndexAlloc = std::allocator; - using IndexType = u32; // Index Type static constexpr size_t NumVertices = 32768; // 8192*4 static constexpr size_t NumIndices = 49152; // 8192*6 }; -class GfxOpenGL : public GfxDriverBase { + +class GfxOpenGL2 : public GfxDriverBase { public: - GfxOpenGL(): GfxDriverBase("OpenGL2") {} - ~GfxOpenGL() {} + GfxOpenGL2() : GfxDriverBase("OpenGL2") {} + ~GfxOpenGL2() {} void SysInit() override; void SysDeinit() override; @@ -38,5 +38,7 @@ class GfxOpenGL : public GfxDriverBase { int pLocTex = 0; int pLocAlfa = 0; int pLocProjection = 0; + static const char* pVertCode; + static const char* pFragCode; }; } // namespace PD \ No newline at end of file diff --git a/backends/include/pd_system/gfx_opengl3.hpp b/backends/include/pd_system/gfx_opengl3.hpp new file mode 100644 index 0000000..da80e53 --- /dev/null +++ b/backends/include/pd_system/gfx_opengl3.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +namespace PD { +struct GfxOpenGL3Config { + // Vertex Allocator + template + using VertexAlloc = std::allocator; + // Index Allocator + template + using IndexAlloc = std::allocator; + + static constexpr size_t NumVertices = 32768; // 8192*4 + static constexpr size_t NumIndices = 49152; // 8192*6 +}; + +class GfxOpenGL3 : public GfxDriverBase { + public: + GfxOpenGL3() : GfxDriverBase("OpenGL3") {} + ~GfxOpenGL3() {} + + void SysInit() override; + void SysDeinit() override; + void Submit(size_t count, size_t start) override; + void BindTexture(TextureID id) override; + void SysReset() override; + TextureID LoadTexture(const std::vector& pixels, int w, int h, + TextureFormat type = TextureFormat::RGBA32, + TextureFilter filter = TextureFilter::Linear) override; + void DeleteTexture(const TextureID& tex) override; + + private: + u32 pShader = 0; + u32 VBO = 0; + u32 IBO = 0; + u32 VAO = 0; + int pLocTex = 0; + int pLocAlfa = 0; + int pLocProjection = 0; + static const char* pVertCode; + static const char* pFragCode; +}; +} // namespace PD \ No newline at end of file diff --git a/backends/include/pd_system/gl-helper.hpp b/backends/include/pd_system/gl-helper.hpp new file mode 100644 index 0000000..bdf304e --- /dev/null +++ b/backends/include/pd_system/gl-helper.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include + +namespace PD { +u32 CreateShaderProgram(const char* vert, const char* frag); +} \ No newline at end of file diff --git a/backends/include/pdsystem b/backends/include/pdsystem new file mode 100644 index 0000000..06daadd --- /dev/null +++ b/backends/include/pdsystem @@ -0,0 +1,6 @@ +#pragma once + +#include +#include +#include +#include diff --git a/backends/source/gfx_citro3d.cpp b/backends/source/gfx_citro3d.cpp new file mode 100644 index 0000000..779a6d8 --- /dev/null +++ b/backends/source/gfx_citro3d.cpp @@ -0,0 +1,69 @@ +// Well yes, i finally try it + +#include + +#if defined(PD_ENABLE_CITRO3D) // && defined(__3DS__) + +#include <3ds.h> +#include + +#include + +namespace PD { +struct GfxCitro3D::Impl {}; + +void GfxCitro3D::SysInit() { + if (impl) return; + PDLOG("GfxCitro3D::SysInit();"); + impl = new Impl(); +} + +void GfxCitro3D::SysDeinit() { + if (!impl) return; + delete impl; + impl = nullptr; + PDLOG("GfxCitro3D::SysDeinit()"); +} + +void GfxCitro3D::Submit(size_t count, size_t start) { + if (!impl) return; +} + +void GfxCitro3D::BindTexture(TextureID id) { + if (!impl) return; +} + +void GfxCitro3D::SysReset() { + if (!impl) return; +} + +TextureID GfxCitro3D::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + if (!impl) return 0; + return 0; +} + +void GfxCitro3D::DeleteTexture(const TextureID& tex) { + if (!tex) return; +} +} // namespace PD +#else +namespace PD { +void GfxCitro3D::SysInit() { + PDLOG( + "GfxCitro3D::SysInit: Citro3D Driver is not included in " + "palladium-system"); +} +void GfxCitro3D::SysDeinit() {} +void GfxCitro3D::Submit(size_t count, size_t start) {} +void GfxCitro3D::BindTexture(TextureID id) {} +void GfxCitro3D::SysReset() {} +TextureID GfxCitro3D::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + return 0; +} +void GfxCitro3D::DeleteTexture(const TextureID& tex) {} +} // namespace PD +#endif \ No newline at end of file diff --git a/backends/source/gfx_directx9.cpp b/backends/source/gfx_directx9.cpp new file mode 100644 index 0000000..ce7a7d7 --- /dev/null +++ b/backends/source/gfx_directx9.cpp @@ -0,0 +1,267 @@ +// Well yes, i finally try it + +#include + +// Sicher ist sicher +#if defined(PD_ENABLE_DIRECTX9) && defined(_WIN32) +#include +#include + +#include + +namespace PD { +static const char* g_vsCode = R"( +float4x4 projection; + +struct VS_IN { + float2 pos : POSITION0; + float2 uv : TEXCOORD0; + float4 col : COLOR0; +}; + +struct VS_OUT { + float4 pos : POSITION0; + float2 uv : TEXCOORD0; + float4 col : COLOR0; +}; + +VS_OUT main(VS_IN input) { + VS_OUT o; + o.pos = mul(projection, float4(input.pos, 0.0, 1.0)); + o.uv = input.uv; + o.col = input.col; + return o; +} +)"; + +static const char* g_psCode = R"( +sampler2D tex : register(s0); +bool alfa; + +struct PS_IN { + float2 uv : TEXCOORD0; + float4 col : COLOR0; +}; + +float4 main(PS_IN input) : COLOR0 { + float4 tc = tex2D(tex, input.uv); + if (alfa) + return float4(input.col.rgb, tc.a * input.col.a); + else + return tc * input.col; +} +)"; + +struct GfxDirectX9::Impl { + IDirect3DDevice9* Device = nullptr; + IDirect3DVertexBuffer9* VBO = nullptr; + IDirect3DIndexBuffer9* IBO = nullptr; + IDirect3DVertexDeclaration9* Decl = nullptr; + IDirect3DVertexShader9* VS = nullptr; + IDirect3DPixelShader9* FS = nullptr; + IDirect3DTexture9* CurrentTex = nullptr; +}; + +void GfxDirectX9::SysInit() { + if (impl) return; + PDLOG("GfxDirectX9::SysInit();"); + impl = new Impl(); + impl->Device = (IDirect3DDevice9*)pDevice; + if (impl->Device) { + D3DVERTEXELEMENT9 elements[]{ + {0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, + 0}, + {0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, + 0}, + {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, + 0}, + D3DDECL_END()}; + impl->Device->CreateVertexDeclaration(elements, &impl->Decl); + impl->Device->CreateVertexBuffer( + GfxDirectX9Config::NumVertices * sizeof(PD::Li::Vertex), + D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &impl->VBO, + nullptr); + impl->Device->CreateIndexBuffer(GfxDirectX9Config::NumIndices * sizeof(u16), + D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, + D3DFMT_INDEX16, D3DPOOL_DEFAULT, &impl->IBO, + nullptr); + ID3DBlob* vsBlob = nullptr; + ID3DBlob* errBlob = nullptr; + HRESULT hr = D3DCompile(g_vsCode, strlen(g_vsCode), nullptr, nullptr, + nullptr, "main", "vs_2_0", 0, 0, &vsBlob, &errBlob); + if (FAILED(hr)) { + PDLOG("Vertex Shader compile error: {}", + errBlob ? (char*)errBlob->GetBufferPointer() : ""); + } else { + impl->Device->CreateVertexShader((DWORD*)vsBlob->GetBufferPointer(), + &impl->VS); + } + if (vsBlob) vsBlob->Release(); + if (errBlob) errBlob->Release(); + + ID3DBlob* psBlob = nullptr; + errBlob = nullptr; + hr = D3DCompile(g_psCode, strlen(g_psCode), nullptr, nullptr, nullptr, + "main", "ps_2_0", 0, 0, &psBlob, &errBlob); + if (FAILED(hr)) { + PDLOG("Pixel Shader compile error: {}", + errBlob ? (char*)errBlob->GetBufferPointer() : ""); + } else { + impl->Device->CreatePixelShader((DWORD*)psBlob->GetBufferPointer(), + &impl->FS); + } + if (psBlob) psBlob->Release(); + if (errBlob) errBlob->Release(); + } else { + PDLOG( + "GfxDirectX9::SysInit Error: pDevice is not set!\nYOu need to include " + "your D3D9 Device as " + "folowing:\nPD::Gfx::UseDriver(D3D9Device);"); + } +} + +void GfxDirectX9::SysDeinit() { + if (!impl || !impl->Device) return; + if (impl->VBO) impl->VBO->Release(); + if (impl->IBO) impl->IBO->Release(); + if (impl->Decl) impl->Decl->Release(); + if (impl->VS) impl->VS->Release(); + if (impl->FS) impl->FS->Release(); + delete impl; + impl = nullptr; + PDLOG("GfxDirectX9::SysDeinit()"); +} + +void GfxDirectX9::Submit(size_t count, size_t start) { + if (!impl || !impl->Device || !impl->VBO || !impl->IBO) return; + + impl->Device->SetVertexShaderConstantF( + 0, reinterpret_cast(&Projection), 4); + + void* vptr; + impl->VBO->Lock(0, 0, &vptr, D3DLOCK_DISCARD); + memcpy(vptr, GetVertexBufPtr(0), CurrentVertex * sizeof(PD::Li::Vertex)); + impl->VBO->Unlock(); + + void* iptr; + impl->IBO->Lock(0, 0, &iptr, D3DLOCK_DISCARD); + memcpy(iptr, GetIndexBufPtr(0), CurrentIndex * sizeof(u16)); + impl->IBO->Unlock(); + + impl->Device->SetStreamSource(0, impl->VBO, 0, sizeof(PD::Li::Vertex)); + impl->Device->SetIndices(impl->IBO); + impl->Device->SetVertexDeclaration(impl->Decl); + impl->Device->SetVertexShader(impl->VS); + impl->Device->SetPixelShader(impl->FS); + + impl->Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, CurrentVertex, + start, count / 3); +} + +void GfxDirectX9::BindTexture(TextureID id) { + if (!impl || !impl->Device) return; + impl->CurrentTex = (IDirect3DTexture9*)id; + impl->Device->SetTexture(0, impl->CurrentTex); + + bool a8 = false; + if (impl->CurrentTex) { + D3DSURFACE_DESC desc; + impl->CurrentTex->GetLevelDesc(0, &desc); + a8 = (desc.Format == D3DFMT_A8); + } + + float v = a8 ? 1.0f : 0.0f; + impl->Device->SetPixelShaderConstantF(0, &v, 1); +} + +void GfxDirectX9::SysReset() { + if (!impl || !impl->Device) return; + + impl->Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + impl->Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + impl->Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); +} + +TextureID GfxDirectX9::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + if (!impl || !impl->Device) return 0; + IDirect3DTexture9* tex = nullptr; + D3DFORMAT fmt = D3DFMT_A8R8G8B8; + if (type == TextureFormat::RGB24) + fmt = D3DFMT_X8R8G8B8; + else if (type == TextureFormat::A8) + fmt = D3DFMT_A8; + + HRESULT hr = impl->Device->CreateTexture(w, h, 1, 0, fmt, D3DPOOL_MANAGED, + &tex, nullptr); + if (FAILED(hr) || !tex) return 0; + + D3DLOCKED_RECT rect; + tex->LockRect(0, &rect, nullptr, 0); + + if (type == TextureFormat::RGB24) { + u8* dstRow = reinterpret_cast(rect.pBits); + for (int y = 0; y < h; ++y) { + u32* dst = reinterpret_cast(dstRow); + for (int x = 0; x < w; ++x) { + u8 r = pixels[(y * w + x) * 3 + 0]; + u8 g = pixels[(y * w + x) * 3 + 1]; + u8 b = pixels[(y * w + x) * 3 + 2]; + dst[x] = (0xFF << 24) | (r << 16) | (g << 8) | b; // X8R8G8B8 + } + dstRow += rect.Pitch; + } + } else if (type == TextureFormat::RGBA32) { + u8* dstRow = reinterpret_cast(rect.pBits); + for (int y = 0; y < h; ++y) { + u32* dst = reinterpret_cast(dstRow); + for (int x = 0; x < w; ++x) { + u8 r = pixels[(y * w + x) * 4 + 0]; + u8 g = pixels[(y * w + x) * 4 + 1]; + u8 b = pixels[(y * w + x) * 4 + 2]; + u8 a = pixels[(y * w + x) * 4 + 3]; + dst[x] = (a << 24) | (r << 16) | (g << 8) | b; // A8R8G8B8 + } + dstRow += rect.Pitch; + } + } else if (type == TextureFormat::A8) { + u8* dstRow = reinterpret_cast(rect.pBits); + for (int y = 0; y < h; ++y) { + memcpy(dstRow, &pixels[y * w], w); + dstRow += rect.Pitch; + } + } + + tex->UnlockRect(0); + + PDLOG("GfxDirectX9::LoadTexture -> [{}] 0x{:X}, [{}, {}]", PD::ivec2(w, h), + (TextureID)tex, type, filter); + return (TextureID)tex; +} + +void GfxDirectX9::DeleteTexture(const TextureID& tex) { + if (!tex) return; + IDirect3DTexture9* t = (IDirect3DTexture9*)tex; + t->Release(); +} +} // namespace PD +#else +namespace PD { +void GfxDirectX9::SysInit() { + PDLOG( + "GfxDirectX9::SysInit: DirectX9 Driver is not included in " + "palladium-system"); +} +void GfxDirectX9::SysDeinit() {} +void GfxDirectX9::Submit(size_t count, size_t start) {} +void GfxDirectX9::BindTexture(TextureID id) {} +void GfxDirectX9::SysReset() {} +TextureID GfxDirectX9::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + return 0; +} +void GfxDirectX9::DeleteTexture(const TextureID& tex) {} +} // namespace PD +#endif \ No newline at end of file diff --git a/backends/source/gfx_opengl.cpp b/backends/source/gfx_opengl2.cpp similarity index 61% rename from backends/source/gfx_opengl.cpp rename to backends/source/gfx_opengl2.cpp index 5e525a9..12919b6 100644 --- a/backends/source/gfx_opengl.cpp +++ b/backends/source/gfx_opengl2.cpp @@ -1,56 +1,13 @@ +#include + +#if defined(PD_ENABLE_OPENGL2) #include -#include - -#include "pd/common.hpp" -#include "pd/drivers/gfx.hpp" +#include +#include namespace PD { -GLuint compileShader(const std::string& source, GLenum type) { - GLuint shader = glCreateShader(type); - const char* src = source.c_str(); - glShaderSource(shader, 1, &src, nullptr); - glCompileShader(shader); - - GLint success; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success) { - char infoLog[512]; - glGetShaderInfoLog(shader, 512, nullptr, infoLog); - std::cerr << "Shader Compilation Error: " << infoLog << std::endl; - } - - return shader; -} - -GLuint createShaderProgram(const std::string& vertexShaderSource, - const std::string& fragmentShaderSource) { - GLuint vertexShader = compileShader(vertexShaderSource, GL_VERTEX_SHADER); - GLuint fragmentShader = - compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER); - - GLuint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); - glLinkProgram(shaderProgram); - - GLint success; - glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); - if (!success) { - char infoLog[512]; - glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); - std::cerr << "Shader Program Linking Error: " << infoLog << std::endl; - } - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - if (success) PDLOG("Shader [{}] compiled sucessfully", shaderProgram); - - return shaderProgram; -} - -const char* vertex_shader = R"( +const char* GfxOpenGL2::pVertCode = R"( #version 120 attribute vec2 pos; @@ -71,7 +28,7 @@ const char* vertex_shader = R"( } )"; -const char* frag_shader = R"( +const char* GfxOpenGL2::pFragCode = R"( #version 120 varying vec2 oUV; @@ -90,7 +47,7 @@ const char* frag_shader = R"( } )"; -void GfxOpenGL::pSetupShaderAttribs(u32 shader) { +void GfxOpenGL2::pSetupShaderAttribs(u32 shader) { GLint _pos = glGetAttribLocation(shader, "pos"); GLint _uv = glGetAttribLocation(shader, "uv"); GLint _color = glGetAttribLocation(shader, "color"); @@ -108,15 +65,15 @@ void GfxOpenGL::pSetupShaderAttribs(u32 shader) { glEnableVertexAttribArray(_color); } -void GfxOpenGL::SysInit() { - pShader = createShaderProgram(vertex_shader, frag_shader); +void GfxOpenGL2::SysInit() { + pShader = CreateShaderProgram(pVertCode, pFragCode); glUseProgram(pShader); glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); - pSetupShaderAttribs(pShader); glGenBuffers(1, &IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); + pSetupShaderAttribs(pShader); pLocTex = glGetUniformLocation(pShader, "tex"); pLocAlfa = glGetUniformLocation(pShader, "alfa"); pLocProjection = glGetUniformLocation(pShader, "projection"); @@ -124,21 +81,20 @@ void GfxOpenGL::SysInit() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); PDLOG( - "GfxOpenGL::SysInit():\n pShader = {}\n pLocTex = {}\n pLocAlfa = " + "GfxOpenGL2::SysInit():\n pShader = {}\n pLocTex = {}\n pLocAlfa = " "{}\n pLocProjection = {}\n VBO = {}\n IBO = {}", pShader, pLocTex, pLocAlfa, pLocProjection, VBO, IBO); } -void GfxOpenGL::SysDeinit() { +void GfxOpenGL2::SysDeinit() { glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &IBO); - PDLOG("GfxOpenGL::SysDeinit()"); + PDLOG("GfxOpenGL2::SysDeinit()"); } -void GfxOpenGL::Submit(size_t count, size_t start) { +void GfxOpenGL2::Submit(size_t count, size_t start) { BindTexture(CurrentTex); glUseProgram(pShader); - pSetupShaderAttribs(pShader); glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data()); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, CurrentVertex * sizeof(PD::Li::Vertex), @@ -148,14 +104,17 @@ void GfxOpenGL::Submit(size_t count, size_t start) { glBufferData(GL_ELEMENT_ARRAY_BUFFER, CurrentIndex * sizeof(PD::u16), GetIndexBufPtr(0), GL_DYNAMIC_DRAW); - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, + pSetupShaderAttribs(pShader); + GLint ibo = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &ibo); + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, reinterpret_cast(start * sizeof(u16))); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); BindTexture(0); } -void GfxOpenGL::BindTexture(TextureID id) { +void GfxOpenGL2::BindTexture(TextureID id) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, (GLuint)id); glUniform1i(pLocTex, 0); @@ -164,25 +123,25 @@ void GfxOpenGL::BindTexture(TextureID id) { glUniform1i(pLocAlfa, fmt == GL_ALPHA); } -void GfxOpenGL::SysReset() { +void GfxOpenGL2::SysReset() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } -TextureID GfxOpenGL::LoadTexture(const std::vector& pixels, int w, - int h, TextureFormat type, - TextureFilter filter) { +TextureID GfxOpenGL2::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { GLuint texID; glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); // Set base format (Always using RGBA as base) GLenum fmt = GL_RGBA; - /*if (type == PD::Li::Texture::Type::RGB24) { + if (type == TextureFormat::RGB24) { fmt = GL_RGB; - } else if (type == PD::Li::Texture::Type::A8) { + } else if (type == TextureFormat::A8) { fmt = GL_ALPHA; - }*/ + } glTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, fmt, GL_UNSIGNED_BYTE, pixels.data()); if (filter == TextureFilter::Linear) { @@ -193,12 +152,33 @@ TextureID GfxOpenGL::LoadTexture(const std::vector& pixels, int w, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } glBindTexture(GL_TEXTURE_2D, 0); - PDLOG("GfxOpenGL::LoadTexture -> [{}] {}", PD::ivec2(w, h), texID); + PDLOG("GfxOpenGL2::LoadTexture -> [{}] {}, [{}, {}]", PD::ivec2(w, h), texID, + type, filter); return texID; } -void GfxOpenGL::DeleteTexture(const TextureID& tex) { +void GfxOpenGL2::DeleteTexture(const TextureID& tex) { GLuint tex_ = tex; glDeleteTextures(1, &tex_); } -} // namespace PD \ No newline at end of file +} // namespace PD +#else +namespace PD { +void GfxOpenGL2::SysInit() { + PDLOG( + "GfxOpenGL2::SysInit: OpenGL2 Driver is not included in " + "palladium-system"); +} +void GfxOpenGL2::SysDeinit() {} +void GfxOpenGL2::Submit(size_t count, size_t start) {} +void GfxOpenGL2::BindTexture(TextureID id) {} +void GfxOpenGL2::SysReset() {} +TextureID GfxOpenGL2::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + return 0; +} +void GfxOpenGL2::DeleteTexture(const TextureID& tex) {} +void GfxOpenGL2::pSetupShaderAttribs(u32 shader) {} +} // namespace PD +#endif \ No newline at end of file diff --git a/backends/source/gfx_opengl3.cpp b/backends/source/gfx_opengl3.cpp new file mode 100644 index 0000000..407780d --- /dev/null +++ b/backends/source/gfx_opengl3.cpp @@ -0,0 +1,180 @@ +#include +#if defined(PD_ENABLE_OPENGL3) +#include + +#include +#include + +namespace PD { +const char* GfxOpenGL3::pVertCode = R"( + #version 330 core + + layout(location = 0) in vec2 pos; + layout(location = 1) in vec2 uv; + layout(location = 2) in vec4 color; + + out vec2 oUV; + out vec4 oColor; + + // Probably forgot about this matrix and + // searched hours for why the rendering isn't working :/ + uniform mat4 projection; + + void main() { + gl_Position = projection*vec4(pos, 0.0, 1.0); + oUV = uv; + oColor = color; + } + )"; + +const char* GfxOpenGL3::pFragCode = R"( + #version 330 core + + in vec2 oUV; + in vec4 oColor; + + uniform sampler2D tex; + uniform bool alfa; + + out vec4 FragColor; + + void main() { + vec4 tc = texture(tex, oUV); + if (alfa) { + FragColor = vec4(oColor.rgb, tc.a * oColor.a); + } else { + FragColor = tc * oColor; + } + } + )"; + +void GfxOpenGL3::SysInit() { + pShader = CreateShaderProgram(pVertCode, pFragCode); + glUseProgram(pShader); + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + glGenBuffers(1, &VBO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(PD::Li::Vertex), + (void*)offsetof(PD::Li::Vertex, pos)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(PD::Li::Vertex), + (void*)offsetof(PD::Li::Vertex, uv)); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(PD::Li::Vertex), + (void*)offsetof(PD::Li::Vertex, color)); + + glGenBuffers(1, &IBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); + + pLocTex = glGetUniformLocation(pShader, "tex"); + pLocAlfa = glGetUniformLocation(pShader, "alfa"); + pLocProjection = glGetUniformLocation(pShader, "projection"); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); + PDLOG( + "GfxOpenGL3::SysInit():\n pShader = {}\n pLocTex = {}\n pLocAlfa = " + "{}\n pLocProjection = {}\n VBO = {}\n IBO = {}, VAO = {}", + pShader, pLocTex, pLocAlfa, pLocProjection, VBO, IBO, VAO); +} + +void GfxOpenGL3::SysDeinit() { + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &IBO); + glDeleteVertexArrays(1, &VAO); + PDLOG("GfxOpenGL3::SysDeinit()"); +} + +void GfxOpenGL3::Submit(size_t count, size_t start) { + BindTexture(CurrentTex); + glUseProgram(pShader); + glUniformMatrix4fv(pLocProjection, 1, GL_FALSE, Projection.m.data()); + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, CurrentVertex * sizeof(PD::Li::Vertex), + GetVertexBufPtr(0), GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, CurrentIndex * sizeof(u16), + GetIndexBufPtr(0), GL_DYNAMIC_DRAW); + + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, + reinterpret_cast(start * sizeof(u16))); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); + BindTexture(0); +} + +void GfxOpenGL3::BindTexture(TextureID id) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, (GLuint)id); + glUniform1i(pLocTex, 0); + GLint fmt = 0; + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &fmt); + glUniform1i(pLocAlfa, fmt == GL_ALPHA); +} + +void GfxOpenGL3::SysReset() { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +TextureID GfxOpenGL3::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + GLuint texID; + glGenTextures(1, &texID); + glBindTexture(GL_TEXTURE_2D, texID); + + // Set base format (Always using RGBA as base) + GLenum fmt = GL_RGBA; + if (type == TextureFormat::RGB24) { + fmt = GL_RGB; + } else if (type == TextureFormat::A8) { + fmt = GL_ALPHA; + } + glTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, fmt, GL_UNSIGNED_BYTE, + pixels.data()); + if (filter == TextureFilter::Linear) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else if (filter == TextureFilter::Nearest) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glBindTexture(GL_TEXTURE_2D, 0); + PDLOG("GfxOpenGL3::LoadTexture -> [{}] {}, [{}, {}]", PD::ivec2(w, h), texID, + type, filter); + return texID; +} + +void GfxOpenGL3::DeleteTexture(const TextureID& tex) { + GLuint tex_ = tex; + glDeleteTextures(1, &tex_); +} +} // namespace PD +#else +namespace PD { +void GfxOpenGL3::SysInit() { + PDLOG( + "GfxOpenGL3::SysInit: OpenGL3 Driver is not included in " + "palladium-system"); +} +void GfxOpenGL3::SysDeinit() {} +void GfxOpenGL3::Submit(size_t count, size_t start) {} +void GfxOpenGL3::BindTexture(TextureID id) {} +void GfxOpenGL3::SysReset() {} +TextureID GfxOpenGL3::LoadTexture(const std::vector& pixels, int w, + int h, TextureFormat type, + TextureFilter filter) { + return 0; +} +void GfxOpenGL3::DeleteTexture(const TextureID& tex) {} +void GfxOpenGL3::pSetupShaderAttribs(u32 shader) {} +} // namespace PD +#endif \ No newline at end of file diff --git a/backends/source/gl-helper.cpp b/backends/source/gl-helper.cpp new file mode 100644 index 0000000..c118927 --- /dev/null +++ b/backends/source/gl-helper.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include + +namespace PD { +GLuint compileShader(const char* src, GLenum type) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, nullptr); + glCompileShader(shader); + + GLint success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetShaderInfoLog(shader, 512, nullptr, infoLog); + std::cerr << "Shader Compilation Error: " << infoLog << std::endl; + } + + return shader; +} +u32 CreateShaderProgram(const char* vert, const char* frag) { + GLuint vertexShader = compileShader(vert, GL_VERTEX_SHADER); + GLuint fragmentShader = compileShader(frag, GL_FRAGMENT_SHADER); + + GLuint shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + + GLint success; + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); + std::cerr << "Shader Program Linking Error: " << infoLog << std::endl; + } + + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + if (success) PDLOG("Shader [{}] compiled sucessfully", shaderProgram); + + return shaderProgram; +} +} // namespace PD \ No newline at end of file diff --git a/include/pd/common.hpp b/include/pd/common.hpp index 4635fde..c8104ac 100644 --- a/include/pd/common.hpp +++ b/include/pd/common.hpp @@ -23,6 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -43,7 +44,7 @@ using u16 = unsigned short; using u32 = unsigned int; using u64 = unsigned long long; using ptr = uintptr_t; -void Log(const std::string& txt); +PD_API void Log(const std::string& txt); template void Log(std::format_string fmt, Args&&... args) { std::string msg = std::format(fmt, std::forward(args)...); diff --git a/include/pd/core/formatters.hpp b/include/pd/core/formatters.hpp index 7cbd8a0..51240fe 100644 --- a/include/pd/core/formatters.hpp +++ b/include/pd/core/formatters.hpp @@ -93,6 +93,6 @@ struct std::formatter : std::formatter { std::format_parse_context::const_iterator end, size_t len, const char* what) { return (end - it >= static_cast(len) && - std::string_view(it, len) == what); + std::string_view(&*it, len) == what); // msvc things... } }; \ No newline at end of file diff --git a/include/pd/drivers/drivers.hpp b/include/pd/drivers/drivers.hpp index 6add8e2..0295bd7 100755 --- a/include/pd/drivers/drivers.hpp +++ b/include/pd/drivers/drivers.hpp @@ -1,4 +1,5 @@ #pragma once +#include +#include #include -#include \ No newline at end of file diff --git a/include/pd/drivers/formatters.hpp b/include/pd/drivers/formatters.hpp new file mode 100644 index 0000000..de2af8f --- /dev/null +++ b/include/pd/drivers/formatters.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + template + auto format(const PD::TextureFilter& value, FormatContext& ctx) const { + std::string_view ret = "Unknown"; + switch (value) { + case PD::TextureFilter::Linear: + ret = "Linear"; + break; + case PD::TextureFilter::Nearest: + ret = "Nearest"; + break; + } + return std::format_to(ctx.out(), "{}", ret); + } +}; + +template <> +struct std::formatter { + constexpr auto parse(std::format_parse_context& ctx) { return ctx.begin(); } + + template + auto format(const PD::TextureFormat& value, FormatContext& ctx) const { + std::string_view ret = "Unknown"; + switch (value) { + case PD::TextureFormat::RGBA32: + ret = "RGBA32"; + break; + case PD::TextureFormat::RGB24: + ret = "RGB24"; + break; + case PD::TextureFormat::A8: + ret = "A8"; + break; + } + return std::format_to(ctx.out(), "{}", ret); + } +}; \ No newline at end of file diff --git a/include/pd/drivers/gfx.hpp b/include/pd/drivers/gfx.hpp index bbc0920..a1a9dd3 100755 --- a/include/pd/drivers/gfx.hpp +++ b/include/pd/drivers/gfx.hpp @@ -19,6 +19,7 @@ enum class TextureFilter { enum class TextureFormat { RGBA32, + RGB24, A8, }; @@ -69,20 +70,17 @@ struct DefaultGfxConfig { // Index Allocator template using IndexAlloc = std::allocator; - using IndexType = u16; // Index Type static constexpr size_t NumVertices = 32768; // 8192*4 static constexpr size_t NumIndices = 49152; // 8192*6 }; template -class PD_API GfxDriverBase : public GfxDriver { +class GfxDriverBase : public GfxDriver { public: - using IndexType = Config::IndexType; using VtxPool = Pool>; - using IdxPool = - Pool>; + using IdxPool = Pool>; GfxDriverBase(std::string_view name = "Default") : GfxDriver(name) {} virtual ~GfxDriverBase() {} @@ -111,17 +109,19 @@ class PD_API GfxDriverBase : public GfxDriver { for (size_t i = 0; i < c.IndexCount; i++) { pIdx[i] = CurrentVertex + c.FirstIndex[i]; } + CurrentIndex += c.IndexCount; + CurrentVertex += c.VertexCount; for (size_t i = 0; i < c.VertexCount; i++) { pVtx[i] = c.FirstVertex[i]; } index++; } - Submit(index - startidx, startidx); + Submit(CurrentIndex - startidx, startidx); } } protected: - IndexType* GetIndexBufPtr(size_t start) { return &pIdxPool[start]; } + u16* GetIndexBufPtr(size_t start) { return &pIdxPool[start]; } Li::Vertex* GetVertexBufPtr(size_t start) { return &pVtxPool[start]; } void ResetPools() override { pVtxPool.Reset(); diff --git a/include/pd/lithium/pools.hpp b/include/pd/lithium/pools.hpp index da82cfd..9887562 100644 --- a/include/pd/lithium/pools.hpp +++ b/include/pd/lithium/pools.hpp @@ -5,8 +5,8 @@ namespace PD { namespace Li { -void InitPools(size_t max_vertices = 32768); -Vertex* AllocateVertices(size_t count); -u16* AllocateIndices(size_t count); +PD_API void InitPools(size_t max_vertices = 32768); +PD_API Vertex* AllocateVertices(size_t count); +PD_API u16* AllocateIndices(size_t count); } // namespace Li } // namespace PD \ No newline at end of file diff --git a/source/common.cpp b/source/common.cpp index b1c1b7a..5d5615c 100644 --- a/source/common.cpp +++ b/source/common.cpp @@ -1,6 +1,6 @@ #include #include -void PD::Log(const std::string& txt) { +PD_API void PD::Log(const std::string& txt) { std::cout << "[PD] " << txt << std::endl; } \ No newline at end of file diff --git a/source/drivers/gfx.cpp b/source/drivers/gfx.cpp index 5e64aeb..dfce080 100755 --- a/source/drivers/gfx.cpp +++ b/source/drivers/gfx.cpp @@ -3,19 +3,20 @@ namespace PD { PD_API std::unique_ptr Gfx::driver; -GfxDriver::GfxDriver(std::string_view name) : DriverInterface(name) {} +PD_API GfxDriver::GfxDriver(std::string_view name) : DriverInterface(name) {} -void GfxDriver::SetViewPort(const ivec2& size) { +PD_API void GfxDriver::SetViewPort(const ivec2& size) { ViewPort = size; Projection = Mat4::Ortho(0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f); } -void GfxDriver::SetViewPort(int x, int y) { + +PD_API void GfxDriver::SetViewPort(int x, int y) { ViewPort.x = x; ViewPort.y = y; Projection = Mat4::Ortho(0.f, ViewPort.x, ViewPort.y, 0.f, 1.f, -1.f); } -void GfxDriver::Reset() { +PD_API void GfxDriver::Reset() { CurrentVertex = 0; CurrentIndex = 0; ResetPools(); diff --git a/source/lithium/pools.cpp b/source/lithium/pools.cpp index e5be94f..256af19 100644 --- a/source/lithium/pools.cpp +++ b/source/lithium/pools.cpp @@ -9,16 +9,16 @@ namespace Li { PD::Pool pVtxPool; PD::Pool pIdxPool; -void InitPools(size_t max_vertices) { +PD_API void InitPools(size_t max_vertices) { pVtxPool.Init(max_vertices); pIdxPool.Init(max_vertices * 2); } -Vertex* AllocateVertices(size_t count) { return pVtxPool.Allocate(count); } +PD_API Vertex* AllocateVertices(size_t count) { return pVtxPool.Allocate(count); } -u16* AllocateIndices(size_t count) { return pIdxPool.Allocate(count); } +PD_API u16* AllocateIndices(size_t count) { return pIdxPool.Allocate(count); } -void ResetPools() { +PD_API void ResetPools() { pVtxPool.Reset(); pIdxPool.Reset(); } diff --git a/tests/gfx/CMakeLists.txt b/tests/gfx/CMakeLists.txt index 4128ff4..8f48b51 100644 --- a/tests/gfx/CMakeLists.txt +++ b/tests/gfx/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.22) project(gfx-tests) add_executable(gfx-tests ${CMAKE_CURRENT_SOURCE_DIR}/source/main.cpp) -target_link_libraries(gfx-tests PRIVATE palladium::palladium pd-system glfw) +target_link_libraries(gfx-tests PRIVATE palladium::palladium pd-system glfw stb) diff --git a/tests/gfx/source/main.cpp b/tests/gfx/source/main.cpp index fc3d2f8..7ebae17 100644 --- a/tests/gfx/source/main.cpp +++ b/tests/gfx/source/main.cpp @@ -3,42 +3,98 @@ #include #include -#include #include #include +#include #include "pd/core/vec2.hpp" #include "pd/lithium/pools.hpp" #include "pd/lithium/vertex.hpp" +#ifdef _WIN32 +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#endif + +#define STB_IMAGE_IMPLEMENTATION +#include + +enum class Driver { + Unknown = 0, + OpenGL2 = 1, + OpenGL3 = 2, + DirectX9 = 3, +}; + +PD::TextureID LoadTex(const std::string& path) { + int w, h, c; + stbi_uc* buf = stbi_load(path.c_str(), &w, &h, &c, 4); + return PD::Gfx::LoadTexture(std::vector(buf, buf + (w * h * 4)), w, + h); +} + class App { public: - App() { + App(Driver d = Driver::OpenGL3) : pDriver(d) { PD::Os::UseDriver(); - PD::Gfx::UseDriver(); glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); - window = glfwCreateWindow(1280, 720, "gfx_tests", nullptr, nullptr); + std::string winname = "gfx_test"; + if (d == Driver::OpenGL2) { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + PD::Gfx::UseDriver(); + winname += " (OpenGL2)"; + } else if (d == Driver::OpenGL3) { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + PD::Gfx::UseDriver(); + winname += " (OpenGL3)"; + } else if (d == Driver::DirectX9) { + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + winname += " (DirectX9)"; + } + window = glfwCreateWindow(1280, 720, winname.c_str(), nullptr, nullptr); glfwMakeContextCurrent(window); - gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress)); + if (d == Driver::OpenGL2 || d == Driver::OpenGL3) { + gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress)); + } +#ifdef _WIN32 + if (d == Driver::DirectX9) { + d3d = Direct3DCreate9(D3D_SDK_VERSION); + auto hwnd = glfwGetWin32Window(window); + D3DPRESENT_PARAMETERS d3dpp = {}; + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = hwnd; + + HRESULT hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING, + &d3dpp, &dx9_device); + if (FAILED(hr)) { + MessageBoxW(nullptr, L"Failed to create D3D9 device", L"Error", MB_OK); + std::abort(); + } + PD::Gfx::UseDriver(dx9_device); + } +#endif glfwSwapInterval(1); PD::Gfx::Init(); PD::Li::InitPools(8192); - std::vector img(16 * 16 * 4, 0xff); - pTex = PD::Gfx::LoadTexture(img, 16, 16); + pTex = LoadTex("icon.png"); + /*std::vector img(16 * 16 * 4, 0xff); + pTex = PD::Gfx::LoadTexture(img, 16, 16);*/ std::cout << "GfxDriver: " << PD::Gfx::GetDriverName() << std::endl; pPool.Init(10); auto cmd = pPool.Allocate(1); cmd->Reserve(4, 6); - cmd->Add(PD::Li::Vertex(PD::fvec2(0, 0), PD::fvec2(0, 0), 0xffffffff)); - cmd->Add(PD::Li::Vertex(PD::fvec2(50, 0), PD::fvec2(1, 0), 0xffffffff)); - cmd->Add(PD::Li::Vertex(PD::fvec2(50, 50), PD::fvec2(1, 1), 0xffffffff)); - cmd->Add(PD::Li::Vertex(PD::fvec2(0, 50), PD::fvec2(0, 1), 0xffffffff)); cmd->Add(0, 1, 2); cmd->Add(0, 2, 3); + cmd->Add(PD::Li::Vertex(PD::fvec2(0, 0), PD::fvec2(0, 0), 0xffffffff)); + cmd->Add(PD::Li::Vertex(PD::fvec2(256, 0), PD::fvec2(1, 0), 0xffffffff)); + cmd->Add(PD::Li::Vertex(PD::fvec2(256, 256), PD::fvec2(1, 1), 0xffffffff)); + cmd->Add(PD::Li::Vertex(PD::fvec2(0, 256), PD::fvec2(0, 1), 0xffffffff)); cmd->Tex = pTex; } ~App() { @@ -49,14 +105,33 @@ class App { void Run() { while (!glfwWindowShouldClose(window)) { - glViewport(0, 0, 1280, 720); - glClearColor(0.1, 0.1, 0.1, 0.1); - glClear(GL_COLOR_BUFFER_BIT); + if (pDriver == Driver::OpenGL2 || pDriver == Driver::OpenGL3) { + glClearColor(0.1, 0.1, 0.1, 0.1); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, 1280, 720); + } else if (pDriver == Driver::DirectX9) { +#ifdef _WIN32 + if (dx9_device) { + dx9_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_XRGB(25, 25, 25), 1.0f, 0); + dx9_device->BeginScene(); + } +#endif + } PD::Gfx::Reset(); PD::Gfx::SetViewPort(1280, 720); PD::Gfx::Draw(pPool); glfwPollEvents(); - glfwSwapBuffers(window); + if (pDriver == Driver::DirectX9) { +#ifdef _WIN32 + if (dx9_device) { + dx9_device->EndScene(); + dx9_device->Present(nullptr, nullptr, nullptr, nullptr); + } +#endif + } else { + glfwSwapBuffers(window); + } } } @@ -64,10 +139,25 @@ class App { GLFWwindow* window = nullptr; PD::Pool pPool; PD::ptr pTex = 0; + Driver pDriver; +#ifdef _WIN32 + IDirect3D9* d3d = nullptr; + IDirect3DDevice9* dx9_device = nullptr; +#endif }; -int main() { - App app; +int main(int argc, char** argv) { + Driver drv = Driver::OpenGL3; + if (argc == 2) { + if (std::string(argv[1]) == "gl2") { + drv = Driver::OpenGL2; + } else if (std::string(argv[1]) == "gl3") { + drv = Driver::OpenGL3; + } else if (std::string(argv[1]) == "dx9") { + drv = Driver::DirectX9; + } + } + App app(drv); app.Run(); return 0; } \ No newline at end of file