#pragma once #include #include #include using LiBackendFlags = PD::u32; enum LiBackendFlags_ { LiBackendFlags_None = 0, LiBackendFlags_FlipUV_Y = 1 << 0, // Essential for font loading }; namespace PD { using TextureID = ptr; enum class TextureFilter { Linear, Nearest, }; enum class TextureFormat { RGBA32, RGB24, A8, }; // Pre interface class class PD_API GfxDriver : public DriverInterface { public: GfxDriver(std::string_view name); virtual ~GfxDriver() = default; virtual void Init() {} virtual void Deinit() { SysDeinit(); } void SetViewPort(const ivec2& size); void SetViewPort(int x, int y); virtual void BindTexture(TextureID id) {} void Reset(); virtual TextureID LoadTexture(const std::vector& pixels, int w, int h, TextureFormat type = TextureFormat::RGBA32, TextureFilter filter = TextureFilter::Linear) { return 0; } virtual void DeleteTexture(const TextureID& tex) {} virtual void Draw(const Pool& commands) {} protected: virtual void SysDeinit() {} virtual void SysInit() {} virtual void SysReset() {} virtual void Submit(size_t count, size_t start) {} virtual void ResetPools() = 0; // Counters size_t CountDrawcalls = 0; size_t CountCommands = 0; size_t CountVertices = 0; size_t CountIndices = 0; size_t CurrentIndex = 0; size_t CurrentVertex = 0; TextureID CurrentTex = 0; Mat4 Projection; ivec2 ViewPort; }; struct DefaultGfxConfig { // 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 }; template class GfxDriverBase : public GfxDriver { public: using VtxPool = Pool>; using IdxPool = Pool>; GfxDriverBase(std::string_view name = "Default") : GfxDriver(name) {} virtual ~GfxDriverBase() {} void Init() override { pVtxPool.Init(Config::NumVertices); pIdxPool.Init(Config::NumIndices); SysInit(); } void Draw(const Pool& commands) override { CountCommands += commands.size(); size_t index = 0; while (index < commands.size()) { CurrentTex = commands[index].Tex; if (!CurrentTex) { index++; continue; } size_t startidx = CurrentIndex; while (index < commands.size() && CurrentTex == commands[index].Tex) { const auto& c = commands[index]; CountVertices += c.VertexCount; CountIndices += c.IndexCount; auto pIdx = pIdxPool.Allocate(c.IndexCount); auto pVtx = pVtxPool.Allocate(c.VertexCount); 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(CurrentIndex - startidx, startidx); } } protected: u16* GetIndexBufPtr(size_t start) { return &pIdxPool[start]; } Li::Vertex* GetVertexBufPtr(size_t start) { return &pVtxPool[start]; } void ResetPools() override { pVtxPool.Reset(); pIdxPool.Reset(); } private: VtxPool pVtxPool; IdxPool pIdxPool; }; class PD_API Gfx { public: Gfx() = default; ~Gfx() = default; template static void UseDriver(Args&&... args) { // assert(driver == nullptr && "OS Driver already set"); driver = std::make_unique(std::forward(args)...); } static void Init() { driver->Init(); } static void Deinit() { driver->Deinit(); } static void SetViewPort(const ivec2& vp) { driver->SetViewPort(vp); } static void SetViewPort(int w, int h) { driver->SetViewPort(w, h); } static void Reset() { driver->Reset(); } static void Draw(const Pool& commands) { driver->Draw(commands); } static TextureID LoadTexture(const std::vector& pixels, int w, int h, TextureFormat type = TextureFormat::RGBA32, TextureFilter filter = TextureFilter::Linear) { return driver->LoadTexture(pixels, w, h, type, filter); } static const char* GetDriverName() { return driver->GetName(); } private: static std::unique_ptr driver; }; } // namespace PD