Add Drawlist
- Add Pool iterator support - Add Pool Expandability - Add Pool::Push - Add Lithium Maths API - Remove InitPools - update spirv-helper
This commit is contained in:
@@ -43,6 +43,8 @@ set(PD_SOURCES
|
|||||||
|
|
||||||
# Lithium
|
# Lithium
|
||||||
source/lithium/pools.cpp
|
source/lithium/pools.cpp
|
||||||
|
source/lithium/math.cpp
|
||||||
|
source/lithium/drawlist.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${PD_BUILD_SHARED})
|
if(${PD_BUILD_SHARED})
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Pool {
|
|||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using iterator = T*;
|
using iterator = T*;
|
||||||
using const_iterator = const iterator*;
|
using const_iterator = const T*;
|
||||||
|
|
||||||
Pool() = default;
|
Pool() = default;
|
||||||
~Pool() {
|
~Pool() {
|
||||||
@@ -36,21 +36,34 @@ class Pool {
|
|||||||
Pool& operator=(Pool&&) = delete;
|
Pool& operator=(Pool&&) = delete;
|
||||||
|
|
||||||
T* Allocate(size_t num = 1) {
|
T* Allocate(size_t num = 1) {
|
||||||
if (CheckLimits(num)) return nullptr;
|
ExpandIf(num);
|
||||||
T* ret = &pData[pPos];
|
T* ret = &pData[pPos];
|
||||||
pPos += num;
|
pPos += num;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckLimits(size_t num) {
|
void Push(const T& elem) {
|
||||||
if ((pPos + num) >= pCap) {
|
T* e = Allocate(1);
|
||||||
throw std::runtime_error(
|
*e = elem;
|
||||||
std::format("[PD::Pool]: Trying to allocate {} elements but this is "
|
|
||||||
"going out of range ({}/{})",
|
|
||||||
num, pPos + num, pCap));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
void ExpandIf(size_t req) {
|
||||||
|
if ((pPos + req) <= pCap) return;
|
||||||
|
size_t ncap = std::max(pCap * 2, pPos + req);
|
||||||
|
T* nu = pAlloc.allocate(ncap);
|
||||||
|
if (pData) {
|
||||||
|
for (size_t i = 0; i < pPos; i++) {
|
||||||
|
std::allocator_traits<Alloc>::construct(
|
||||||
|
pAlloc, &nu[i], std::move_if_noexcept(pData[i]));
|
||||||
|
}
|
||||||
|
pAlloc.deallocate(pData, pCap);
|
||||||
|
}
|
||||||
|
for (size_t i = pPos; i < ncap; i++) {
|
||||||
|
std::allocator_traits<Alloc>::construct(pAlloc, &nu[i]);
|
||||||
|
}
|
||||||
|
PDLOG("Pool::ExpandIf({}): {} -> {}", req, pCap, ncap);
|
||||||
|
pData = nu;
|
||||||
|
pCap = ncap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
@@ -67,6 +80,10 @@ class Pool {
|
|||||||
size_t capacity() const { return pCap; }
|
size_t capacity() const { return pCap; }
|
||||||
T& at(size_t idx) { return pData[idx]; }
|
T& at(size_t idx) { return pData[idx]; }
|
||||||
const T& at(size_t idx) const { return pData[idx]; }
|
const T& at(size_t idx) const { return pData[idx]; }
|
||||||
|
iterator begin() { return pData; }
|
||||||
|
iterator end() { return pData + pPos; }
|
||||||
|
const_iterator begin() const { return pData; }
|
||||||
|
const_iterator end() const { return pData + pPos; }
|
||||||
|
|
||||||
T& operator[](size_t idx) { return at(idx); }
|
T& operator[](size_t idx) { return at(idx); }
|
||||||
const T& operator[](size_t idx) const { return at(idx); }
|
const T& operator[](size_t idx) const { return at(idx); }
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class PD_API GfxDriver : public DriverInterface {
|
|||||||
}
|
}
|
||||||
virtual void DeleteTexture(const Li::Texture& tex) {}
|
virtual void DeleteTexture(const Li::Texture& tex) {}
|
||||||
virtual void Draw(const Pool<Li::Command>& commands) {}
|
virtual void Draw(const Pool<Li::Command>& commands) {}
|
||||||
|
Li::Texture::Ptr GetWhiteTexture() { return &pWhite; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void SysDeinit() {}
|
virtual void SysDeinit() {}
|
||||||
@@ -55,6 +56,7 @@ class PD_API GfxDriver : public DriverInterface {
|
|||||||
Mat4 Projection;
|
Mat4 Projection;
|
||||||
ivec2 ViewPort;
|
ivec2 ViewPort;
|
||||||
std::unordered_map<TextureID, Li::Texture> pTextureRegestry;
|
std::unordered_map<TextureID, Li::Texture> pTextureRegestry;
|
||||||
|
Li::Texture pWhite;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DefaultGfxConfig {
|
struct DefaultGfxConfig {
|
||||||
@@ -79,9 +81,11 @@ class GfxDriverBase : public GfxDriver {
|
|||||||
virtual ~GfxDriverBase() {}
|
virtual ~GfxDriverBase() {}
|
||||||
|
|
||||||
void Init() override {
|
void Init() override {
|
||||||
pVtxPool.Init(Config::NumVertices);
|
// pVtxPool.Init(Config::NumVertices);
|
||||||
pIdxPool.Init(Config::NumIndices);
|
// pIdxPool.Init(Config::NumIndices);
|
||||||
SysInit();
|
SysInit();
|
||||||
|
std::vector<u8> img(16 * 16 * 4, 0xff);
|
||||||
|
pWhite = LoadTexture(img, 16, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(const Pool<Li::Command>& commands) override {
|
void Draw(const Pool<Li::Command>& commands) override {
|
||||||
@@ -90,11 +94,12 @@ class GfxDriverBase : public GfxDriver {
|
|||||||
while (index < commands.size()) {
|
while (index < commands.size()) {
|
||||||
CurrentTex = commands[index].Tex;
|
CurrentTex = commands[index].Tex;
|
||||||
if (!CurrentTex) {
|
if (!CurrentTex) {
|
||||||
index++;
|
CurrentTex = pWhite.GetID();
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
size_t startidx = CurrentIndex;
|
size_t startidx = CurrentIndex;
|
||||||
while (index < commands.size() && CurrentTex == commands[index].Tex) {
|
while (index < commands.size() &&
|
||||||
|
(CurrentTex == commands[index].Tex ||
|
||||||
|
(CurrentTex == pWhite.GetID() && commands[index].Tex == 0))) {
|
||||||
const auto& c = commands[index];
|
const auto& c = commands[index];
|
||||||
CountVertices += c.VertexCount;
|
CountVertices += c.VertexCount;
|
||||||
CountIndices += c.IndexCount;
|
CountIndices += c.IndexCount;
|
||||||
@@ -155,6 +160,9 @@ class PD_API Gfx {
|
|||||||
static void DeleteTexture(const Li::Texture& tex) {
|
static void DeleteTexture(const Li::Texture& tex) {
|
||||||
driver->DeleteTexture(tex);
|
driver->DeleteTexture(tex);
|
||||||
}
|
}
|
||||||
|
static Li::Texture::Ptr GetWhiteTexture() {
|
||||||
|
return driver->GetWhiteTexture();
|
||||||
|
}
|
||||||
|
|
||||||
static const char* GetDriverName() { return driver->GetName(); }
|
static const char* GetDriverName() { return driver->GetName(); }
|
||||||
|
|
||||||
|
|||||||
116
include/pd/lithium/drawlist.hpp
Normal file
116
include/pd/lithium/drawlist.hpp
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pd/lithium/command.hpp>
|
||||||
|
#include <pd/lithium/texture.hpp>
|
||||||
|
|
||||||
|
using LiPathRectFlags = PD::u32;
|
||||||
|
|
||||||
|
enum LiPathRectFlags_ : PD::u32 {
|
||||||
|
LiPathRectFlags_None = 0,
|
||||||
|
LiPathRectFlags_KeepTopLeft = 1 << 0,
|
||||||
|
LiPathRectFlags_KeepTopRight = 1 << 1,
|
||||||
|
LiPathRectFlags_KeepBotRight = 1 << 2,
|
||||||
|
LiPathRectFlags_KeepBotLeft = 1 << 3,
|
||||||
|
LiPathRectFlags_KeepTop =
|
||||||
|
LiPathRectFlags_KeepTopLeft | LiPathRectFlags_KeepTopRight,
|
||||||
|
LiPathRectFlags_KeepBot =
|
||||||
|
LiPathRectFlags_KeepBotLeft | LiPathRectFlags_KeepBotRight,
|
||||||
|
LiPathRectFlags_KeepLeft =
|
||||||
|
LiPathRectFlags_KeepTopLeft | LiPathRectFlags_KeepBotLeft,
|
||||||
|
LiPathRectFlags_KeepRight =
|
||||||
|
LiPathRectFlags_KeepTopRight | LiPathRectFlags_KeepBotRight,
|
||||||
|
};
|
||||||
|
|
||||||
|
using LiDrawFlags = PD::u32;
|
||||||
|
enum LiDrawFlags_ : PD::u32 {
|
||||||
|
LiDrawFlags_None = 0,
|
||||||
|
LiDrawFlags_Close = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
using LiTextFlags = PD::u32;
|
||||||
|
enum LiTextFlags_ : PD::u32 {
|
||||||
|
LiTextFlags_None = 0, ///< Do nothing
|
||||||
|
LiTextFlags_AlignRight = 1 << 0, ///< Align Right of position
|
||||||
|
LiTextFlags_AlignMid = 1 << 1, ///< Align in the middle of pos and box
|
||||||
|
LiTextFlags_Shaddow = 1 << 2, ///< Draws the text twice to create shaddow
|
||||||
|
LiTextFlags_Wrap = 1 << 3, ///< Wrap Text: May be runs better with TMS
|
||||||
|
LiTextFlags_Short = 1 << 4, ///< Short Text: May be runs better with TMS
|
||||||
|
LiTextFlags_Scroll = 1 << 5, ///< Not implemented [scoll text if to long]
|
||||||
|
LiTextFlags_NoOOS = 1 << 6, ///< No Out of Screen Rendering
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace PD {
|
||||||
|
namespace Li {
|
||||||
|
class PD_API Drawlist {
|
||||||
|
public:
|
||||||
|
Drawlist();
|
||||||
|
~Drawlist();
|
||||||
|
|
||||||
|
/** Baisc */
|
||||||
|
|
||||||
|
void Merge(Drawlist& other);
|
||||||
|
void Copy(Drawlist& other);
|
||||||
|
void Optimize();
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
/** Command Allocation */
|
||||||
|
Command& NewCommand();
|
||||||
|
|
||||||
|
/** Path API */
|
||||||
|
void PathAdd(const fvec2& point) { pPath.Push(point); }
|
||||||
|
void PathAdd(float x, float y) { pPath.Push(fvec2(x, y)); }
|
||||||
|
void PathClear() { pPath.Reset(); }
|
||||||
|
/**
|
||||||
|
* @brief Reserve memory for the next PathAdd uses
|
||||||
|
* @note As path will autoexpant and keep the size this func is
|
||||||
|
* only for special use cases
|
||||||
|
*/
|
||||||
|
void PathReserve(size_t num) { pPath.ExpandIf(num); }
|
||||||
|
void PathStroke(u32 color, int t = 1, LiDrawFlags flags = LiDrawFlags_None);
|
||||||
|
void PathFill(u32 color);
|
||||||
|
void PathArcToN(const fvec2& c, float r, float amin, float amax, int s);
|
||||||
|
void PathFastArcToN(const fvec2& c, float r, float amin, float amax, int s);
|
||||||
|
void PathRect(const fvec2& tl, const fvec2& br, float r = 0.f);
|
||||||
|
void PathRectEx(const fvec2& tl, const fvec2& br, float r = 0.f,
|
||||||
|
LiPathRectFlags flags = LiPathRectFlags_None);
|
||||||
|
|
||||||
|
/** Texture Handling */
|
||||||
|
void BindTexture(const Texture& tex);
|
||||||
|
void UnbindTexture() { pCurrentTexture = Texture(); }
|
||||||
|
|
||||||
|
/** Data geters */
|
||||||
|
const Pool<Command>& Data() const { return pCommands; }
|
||||||
|
operator const Pool<Command>&() const { return pCommands; }
|
||||||
|
|
||||||
|
/** Drawing functions */
|
||||||
|
void DrawRect(const fvec2& pos, const fvec2& size, u32 color, int t = 1);
|
||||||
|
void DrawRectFilled(const fvec2& pos, const fvec2& size, u32 color);
|
||||||
|
void DrawTriangle(const fvec2& a, const fvec2& b, const fvec2& c, u32 color,
|
||||||
|
int t = 1);
|
||||||
|
void DrawTriangleFilled(const fvec2& a, const fvec2& b, const fvec2& c,
|
||||||
|
u32 color);
|
||||||
|
void DrawCircle(const fvec2& center, float rad, u32 color, int num_segments,
|
||||||
|
int t = 1);
|
||||||
|
void DrawCircleFilled(const fvec2& center, float rad, u32 color,
|
||||||
|
int num_segments);
|
||||||
|
void DrawText(const fvec2& p, const char* text, u32 color);
|
||||||
|
void DrawTextEx(const fvec2& p, const char* text, u32 color,
|
||||||
|
LiTextFlags flags, const fvec2& box = fvec2(0.f));
|
||||||
|
|
||||||
|
void DrawPolyLine(const Pool<fvec2>& points, u32 color,
|
||||||
|
LiDrawFlags flags = LiDrawFlags_None, int t = 1);
|
||||||
|
void DrawConvexPolyFilled(const Pool<fvec2>& points, u32 color);
|
||||||
|
|
||||||
|
void PrimQuad(Command& cmd, const Rect& quad, const Rect& uv, u32 color);
|
||||||
|
void PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, u32 color);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Texture pCurrentTexture;
|
||||||
|
Pool<Command> pCommands;
|
||||||
|
Pool<fvec2> pPath;
|
||||||
|
Pool<Vertex> pVertices;
|
||||||
|
Pool<u16> pIndices;
|
||||||
|
};
|
||||||
|
} // namespace Li
|
||||||
|
} // namespace PD
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pd/lithium/command.hpp>
|
#include <pd/lithium/command.hpp>
|
||||||
|
#include <pd/lithium/drawlist.hpp>
|
||||||
|
#include <pd/lithium/math.hpp>
|
||||||
#include <pd/lithium/pools.hpp>
|
#include <pd/lithium/pools.hpp>
|
||||||
#include <pd/lithium/vertex.hpp>
|
#include <pd/lithium/vertex.hpp>
|
||||||
18
include/pd/lithium/math.hpp
Normal file
18
include/pd/lithium/math.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pd/core/core.hpp>
|
||||||
|
#include <pd/lithium/rect.hpp>
|
||||||
|
|
||||||
|
namespace PD {
|
||||||
|
namespace Li {
|
||||||
|
namespace Math {
|
||||||
|
PD_API bool InBounds(const fvec2& pos, const fvec2& size, const fvec4& rect);
|
||||||
|
PD_API bool InBounds(const fvec2& pos, const fvec4& rect);
|
||||||
|
PD_API bool InBounds(const fvec2& a, const fvec2& b, const fvec2& c,
|
||||||
|
const fvec4& rect);
|
||||||
|
PD_API void RotateCorner(fvec2& pos, float sinus, float cosinus);
|
||||||
|
PD_API Rect PrimRect(const fvec2& pos, const fvec2& size, float angle = 0.f);
|
||||||
|
PD_API Rect PrimLine(const fvec2& a, const fvec2& b, int t = 1);
|
||||||
|
} // namespace Math
|
||||||
|
} // namespace Li
|
||||||
|
} // namespace PD
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
namespace PD {
|
namespace PD {
|
||||||
namespace Li {
|
namespace Li {
|
||||||
PD_API void InitPools(size_t max_vertices = 32768);
|
|
||||||
PD_API Vertex* AllocateVertices(size_t count);
|
PD_API Vertex* AllocateVertices(size_t count);
|
||||||
PD_API u16* AllocateIndices(size_t count);
|
PD_API u16* AllocateIndices(size_t count);
|
||||||
|
PD_API void ResetPools();
|
||||||
} // namespace Li
|
} // namespace Li
|
||||||
} // namespace PD
|
} // namespace PD
|
||||||
@@ -18,6 +18,7 @@ enum class TextureFormat {
|
|||||||
namespace Li {
|
namespace Li {
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
|
using Ptr = Texture*;
|
||||||
Texture() : pID(0), pSize(0, 0), pUV(fvec4(0, 0, 1, 1)) {}
|
Texture() : pID(0), pSize(0, 0), pUV(fvec4(0, 0, 1, 1)) {}
|
||||||
Texture(TextureID id, ivec2 size)
|
Texture(TextureID id, ivec2 size)
|
||||||
: pID(id), pSize(size), pUV(fvec4(0, 0, 1, 1)) {}
|
: pID(id), pSize(size), pUV(fvec4(0, 0, 1, 1)) {}
|
||||||
|
|||||||
285
source/lithium/drawlist.cpp
Normal file
285
source/lithium/drawlist.cpp
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
#include <pd/drivers/gfx.hpp>
|
||||||
|
#include <pd/lithium/drawlist.hpp>
|
||||||
|
#include <pd/lithium/math.hpp>
|
||||||
|
|
||||||
|
namespace PD {
|
||||||
|
namespace Li {
|
||||||
|
PD_API Drawlist::Drawlist() { Clear(); }
|
||||||
|
|
||||||
|
PD_API Drawlist::~Drawlist() { Clear(); }
|
||||||
|
|
||||||
|
PD_API void Drawlist::Merge(Drawlist& other) {}
|
||||||
|
|
||||||
|
PD_API void Drawlist::Copy(Drawlist& other) {}
|
||||||
|
|
||||||
|
PD_API void Drawlist::Optimize() {}
|
||||||
|
|
||||||
|
PD_API void Drawlist::Clear() {
|
||||||
|
UnbindTexture();
|
||||||
|
pPath.Reset();
|
||||||
|
pVertices.Reset();
|
||||||
|
pIndices.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Command Allocation */
|
||||||
|
PD_API Command& Drawlist::NewCommand() {
|
||||||
|
auto cmd = pCommands.Allocate(1);
|
||||||
|
cmd->Tex = pCurrentTexture.GetID();
|
||||||
|
return *cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::BindTexture(const Texture& tex) { pCurrentTexture = tex; }
|
||||||
|
|
||||||
|
/** Path API */
|
||||||
|
PD_API void Drawlist::PathStroke(u32 color, int t, LiDrawFlags flags) {
|
||||||
|
DrawPolyLine(pPath, color, flags, t);
|
||||||
|
PathClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PathFill(u32 color) {
|
||||||
|
DrawConvexPolyFilled(pPath, color);
|
||||||
|
PathClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PathArcToN(const fvec2& c, float r, float amin,
|
||||||
|
float amax, int s) {
|
||||||
|
// Path.push_back(c);
|
||||||
|
PathReserve(s + 1);
|
||||||
|
for (int i = 0; i < s; i++) {
|
||||||
|
float a = amin + ((float)i / (float)s) * (amax - amin);
|
||||||
|
PathAdd(vec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PathFastArcToN(const fvec2& c, float r, float amin,
|
||||||
|
float amax, int s) {
|
||||||
|
/**
|
||||||
|
* Funcion with less division overhead
|
||||||
|
* Usefull for stuff where a lot of calculations are required
|
||||||
|
*/
|
||||||
|
float d = (amax - amin) / s;
|
||||||
|
PathReserve(s + 1);
|
||||||
|
for (int i = 0; i <= s; i++) {
|
||||||
|
float a = amin + i * d;
|
||||||
|
PathAdd(fvec2(c.x + std::cos(a) * r, c.y + std::sin(a) * r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PathRect(const fvec2& tl, const fvec2& br, float r) {
|
||||||
|
if (r == 0.f) {
|
||||||
|
PathAdd(tl);
|
||||||
|
PathAdd(vec2(br.x, tl.y));
|
||||||
|
PathAdd(br);
|
||||||
|
PathAdd(vec2(tl.x, br.y));
|
||||||
|
} else {
|
||||||
|
float r = std::min({r, (br.x - tl.x) * 0.5f, (br.y - tl.y) * 0.5f});
|
||||||
|
/** Calculate Optimal segment count automatically */
|
||||||
|
float corner = M_PI * 0.5f;
|
||||||
|
int segments = std::max(3, int(std::ceil(corner / (6.0f * M_PI / 180.0f))));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Correctly render filled shapes with Paths API
|
||||||
|
* The Commands need to be setup clockwise
|
||||||
|
*/
|
||||||
|
/** Top Left */
|
||||||
|
PathAdd(vec2(tl.x + r, tl.y));
|
||||||
|
PathFastArcToN(vec2(br.x - r, tl.y + r), r, -M_PI / 2.0f, 0.0f, segments);
|
||||||
|
/** Top Right */
|
||||||
|
PathAdd(vec2(br.x, br.y - r));
|
||||||
|
PathFastArcToN(vec2(br.x - r, br.y - r), r, 0.0f, M_PI / 2.0f, segments);
|
||||||
|
/** Bottom Right */
|
||||||
|
PathAdd(vec2(tl.x + r, br.y));
|
||||||
|
PathFastArcToN(vec2(tl.x + r, br.y - r), r, M_PI / 2.0f, M_PI, segments);
|
||||||
|
/** Bottom Left */
|
||||||
|
PathAdd(vec2(tl.x, tl.y + r));
|
||||||
|
PathFastArcToN(vec2(tl.x + r, tl.y + r), r, M_PI, 3.0f * M_PI / 2.0f,
|
||||||
|
segments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PathRectEx(const fvec2& tl, const fvec2& br, float r,
|
||||||
|
LiPathRectFlags flags) {
|
||||||
|
if (r == 0.f) {
|
||||||
|
PathAdd(tl);
|
||||||
|
PathAdd(vec2(br.x, tl.y));
|
||||||
|
PathAdd(br);
|
||||||
|
PathAdd(vec2(tl.x, br.y));
|
||||||
|
} else {
|
||||||
|
float r = std::min({r, (br.x - tl.x) * 0.5f, (br.y - tl.y) * 0.5f});
|
||||||
|
/** Calculate Optimal segment count automatically */
|
||||||
|
float corner = M_PI * 0.5f;
|
||||||
|
int segments = std::max(3, int(std::ceil(corner / (6.0f * M_PI / 180.0f))));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Correctly render filled shapes with Paths API
|
||||||
|
* The Commands need to be setup clockwise
|
||||||
|
*/
|
||||||
|
/** Top Left */
|
||||||
|
if (flags & LiPathRectFlags_KeepTopLeft) {
|
||||||
|
PathAdd(tl);
|
||||||
|
} else {
|
||||||
|
PathAdd(vec2(tl.x + r, tl.y));
|
||||||
|
PathFastArcToN(vec2(br.x - r, tl.y + r), r, -M_PI / 2.0f, 0.0f, segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Top Right */
|
||||||
|
if (flags & LiPathRectFlags_KeepTopRight) {
|
||||||
|
PathAdd(vec2(br.x, tl.y));
|
||||||
|
} else {
|
||||||
|
PathAdd(vec2(br.x, br.y - r));
|
||||||
|
PathFastArcToN(vec2(br.x - r, br.y - r), r, 0.0f, M_PI / 2.0f, segments);
|
||||||
|
}
|
||||||
|
/** Bottom Right */
|
||||||
|
if (flags & LiPathRectFlags_KeepBotRight) {
|
||||||
|
PathAdd(br);
|
||||||
|
} else {
|
||||||
|
PathAdd(vec2(tl.x + r, br.y));
|
||||||
|
PathFastArcToN(vec2(tl.x + r, br.y - r), r, M_PI / 2.0f, M_PI, segments);
|
||||||
|
}
|
||||||
|
/** Bottom Left */
|
||||||
|
if (flags & LiPathRectFlags_KeepBotLeft) {
|
||||||
|
PathAdd(vec2(tl.x, br.y));
|
||||||
|
} else {
|
||||||
|
PathAdd(vec2(tl.x, tl.y + r));
|
||||||
|
PathFastArcToN(vec2(tl.x + r, tl.y + r), r, M_PI, 3.0f * M_PI / 2.0f,
|
||||||
|
segments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Drawing functions */
|
||||||
|
PD_API void Drawlist::DrawRect(const fvec2& pos, const fvec2& size, u32 color,
|
||||||
|
int t) {
|
||||||
|
PathRect(pos, pos + size);
|
||||||
|
PathStroke(color, t, LiDrawFlags_Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawRectFilled(const fvec2& pos, const fvec2& size,
|
||||||
|
u32 color) {
|
||||||
|
PathRect(pos, pos + size);
|
||||||
|
PathFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawTriangle(const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, u32 color, int t) {
|
||||||
|
PathAdd(a);
|
||||||
|
PathAdd(b);
|
||||||
|
PathAdd(c);
|
||||||
|
PathStroke(color, t, LiDrawFlags_Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawTriangleFilled(const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, u32 color) {
|
||||||
|
PathAdd(a);
|
||||||
|
PathAdd(b);
|
||||||
|
PathAdd(c);
|
||||||
|
PathFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawCircle(const fvec2& center, float rad, u32 color,
|
||||||
|
int num_segments, int t) {
|
||||||
|
if (num_segments <= 0) {
|
||||||
|
// Auto Segment
|
||||||
|
} else {
|
||||||
|
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
|
||||||
|
PathArcToN(center, rad, 0.f, am, num_segments);
|
||||||
|
}
|
||||||
|
UnbindTexture(); // Only Solid Color Supported
|
||||||
|
PathStroke(color, t, LiDrawFlags_Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawCircleFilled(const fvec2& center, float rad,
|
||||||
|
u32 color, int num_segments) {
|
||||||
|
if (num_segments <= 0) {
|
||||||
|
// Auto Segment
|
||||||
|
} else {
|
||||||
|
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
|
||||||
|
PathArcToN(center, rad, 0.f, am, num_segments);
|
||||||
|
}
|
||||||
|
PathFill(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawText(const fvec2& p, const char* text, u32 color) {}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawTextEx(const fvec2& p, const char* text, u32 color,
|
||||||
|
LiTextFlags flags, const fvec2& box) {}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawPolyLine(const Pool<fvec2>& points, u32 color,
|
||||||
|
LiDrawFlags flags, int t) {
|
||||||
|
if (points.size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UnbindTexture();
|
||||||
|
auto& cmd = NewCommand();
|
||||||
|
bool close = (flags & (1 << 0));
|
||||||
|
int num_points = close ? (int)points.size() : (int)points.size() - 1;
|
||||||
|
if (flags & (1 << 1)) {
|
||||||
|
// TODO: Find a way to draw less garbage looking lines
|
||||||
|
} else {
|
||||||
|
// Non antialiased lines look awful when rendering with thickness != 1
|
||||||
|
for (int i = 0; i < num_points; i++) {
|
||||||
|
int j = (i + 1) == (int)points.size() ? 0 : (i + 1);
|
||||||
|
auto line = Math::PrimLine(points[i], points[j], t);
|
||||||
|
this->PrimQuad(cmd, line, vec4(0.f, 1.f, 1.f, 0.f), color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::DrawConvexPolyFilled(const Pool<fvec2>& points,
|
||||||
|
u32 color) {
|
||||||
|
if (points.size() < 3) {
|
||||||
|
return; // Need at least three points
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support for Custom Textures (UV calculation)
|
||||||
|
float minX = points[0].x, minY = points[0].y;
|
||||||
|
float maxX = minX, maxY = minY;
|
||||||
|
// Check for the max and min Positions
|
||||||
|
for (const auto& it : points) {
|
||||||
|
if (it.x < minX) minX = it.x;
|
||||||
|
if (it.y < minY) minY = it.y;
|
||||||
|
if (it.x > maxX) maxX = it.x;
|
||||||
|
if (it.y > maxY) maxY = it.y;
|
||||||
|
}
|
||||||
|
// Get Short defines for UV
|
||||||
|
// (Bottom Right is not required)
|
||||||
|
auto uv_tl = pCurrentTexture.GetUV().TopLeft();
|
||||||
|
auto uv_tr = pCurrentTexture.GetUV().TopRight();
|
||||||
|
auto uv_bl = pCurrentTexture.GetUV().BotLeft();
|
||||||
|
|
||||||
|
auto& cmd = NewCommand();
|
||||||
|
cmd.Reserve(points.size(), (points.size() - 2) * 3);
|
||||||
|
// Render
|
||||||
|
for (int i = 2; i < (int)points.size(); i++) {
|
||||||
|
cmd.Add(0, i, i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)points.size(); i++) {
|
||||||
|
// Calculate U and V coords
|
||||||
|
float u =
|
||||||
|
uv_tl.x + ((points[i].x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
|
||||||
|
float v =
|
||||||
|
uv_tl.y + ((points[i].y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
|
||||||
|
cmd.Add(Vertex(points[i], fvec2(u, v), color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PrimQuad(Command& cmd, const Rect& quad, const Rect& uv,
|
||||||
|
u32 color) {
|
||||||
|
cmd.Add(2, 1, 0);
|
||||||
|
cmd.Add(3, 2, 0);
|
||||||
|
cmd.Add(Vertex(quad.TopLeft(), uv.TopLeft(), color));
|
||||||
|
cmd.Add(Vertex(quad.TopRight(), uv.TopRight(), color));
|
||||||
|
cmd.Add(Vertex(quad.BotRight(), uv.BotRight(), color));
|
||||||
|
cmd.Add(Vertex(quad.BotLeft(), uv.BotLeft(), color));
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void Drawlist::PrimTriangle(Command& cmd, const fvec2& a, const fvec2& b,
|
||||||
|
const fvec2& c, u32 color) {
|
||||||
|
cmd.Add(2, 1, 0);
|
||||||
|
cmd.Add(Vertex(a, vec2(0.f, 1.f), color));
|
||||||
|
cmd.Add(Vertex(b, vec2(1.f, 1.f), color));
|
||||||
|
cmd.Add(Vertex(c, vec2(1.f, 0.f), color));
|
||||||
|
}
|
||||||
|
} // namespace Li
|
||||||
|
} // namespace PD
|
||||||
65
source/lithium/math.cpp
Normal file
65
source/lithium/math.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include <pd/lithium/math.hpp>
|
||||||
|
|
||||||
|
namespace PD {
|
||||||
|
namespace Li {
|
||||||
|
namespace Math {
|
||||||
|
PD_API bool InBounds(const fvec2& pos, const fvec2& size, const fvec4& rect) {
|
||||||
|
return (pos.x + size.x >= rect.x && pos.y + size.y >= rect.y &&
|
||||||
|
pos.x <= rect.z && pos.y <= rect.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API bool InBounds(const fvec2& pos, const fvec4& rect) {
|
||||||
|
return (pos.x > rect.x && pos.x < rect.x + rect.z && pos.y > rect.y &&
|
||||||
|
pos.y < rect.y + rect.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API bool InBounds(const fvec2& a, const fvec2& b, const fvec2& c,
|
||||||
|
const fvec4& rect) {
|
||||||
|
return ((a.x < rect.z && b.x < rect.z && c.x < rect.z) ||
|
||||||
|
(a.y < rect.w && b.y < rect.w && c.y < rect.w) ||
|
||||||
|
(a.x > 0 && b.x > 0 && c.x > 0) || (a.y > 0 && b.y > 0 && c.y > 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API void RotateCorner(fvec2& pos, float sinus, float cosinus) {
|
||||||
|
float x = pos.x * cosinus - pos.y * sinus;
|
||||||
|
float y = pos.y * cosinus - pos.x * sinus;
|
||||||
|
pos = fvec2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API Rect PrimRect(const fvec2& pos, const fvec2& size, float a) {
|
||||||
|
fvec2 c = size * 0.5f; // Center
|
||||||
|
fvec2 corner[4] = {
|
||||||
|
fvec2(-c.x, -c.y),
|
||||||
|
fvec2(-c.x + size.x, -c.y),
|
||||||
|
fvec2(-c.x, -c.y + size.y),
|
||||||
|
fvec2(-c.x + size.x, -c.y + size.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only rotate if required
|
||||||
|
if (a != 0.f) {
|
||||||
|
float s = std::sin(a);
|
||||||
|
float co = std::cos(a);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
RotateCorner(corner[i], s, co);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return Result
|
||||||
|
return Rect(corner[0] + pos + c, corner[1] + pos + c, corner[2] + pos + c,
|
||||||
|
corner[3] + pos + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
PD_API Rect PrimLine(const fvec2& a, const fvec2& b, int t) {
|
||||||
|
// Using the vec maths api makes the code as short as it is
|
||||||
|
vec2 dir = a - b;
|
||||||
|
float len = dir.Len();
|
||||||
|
vec2 unit_dir = dir / len;
|
||||||
|
vec2 perpendicular(-unit_dir.y, unit_dir.x);
|
||||||
|
vec2 off = perpendicular * ((float)t * 0.5f);
|
||||||
|
|
||||||
|
return Rect(a + off, b + off, a - off, b - off);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Math
|
||||||
|
} // namespace Li
|
||||||
|
} // namespace PD
|
||||||
@@ -6,11 +6,6 @@ namespace Li {
|
|||||||
PD::Pool<Vertex> pVtxPool;
|
PD::Pool<Vertex> pVtxPool;
|
||||||
PD::Pool<u16> pIdxPool;
|
PD::Pool<u16> pIdxPool;
|
||||||
|
|
||||||
PD_API void InitPools(size_t max_vertices) {
|
|
||||||
pVtxPool.Init(max_vertices);
|
|
||||||
pIdxPool.Init(max_vertices * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
PD_API Vertex* AllocateVertices(size_t count) {
|
PD_API Vertex* AllocateVertices(size_t count) {
|
||||||
return pVtxPool.Allocate(count);
|
return pVtxPool.Allocate(count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class App {
|
|||||||
glfwSwapInterval(1);
|
glfwSwapInterval(1);
|
||||||
#else
|
#else
|
||||||
gfxInitDefault();
|
gfxInitDefault();
|
||||||
|
consoleInit(GFX_BOTTOM, nullptr);
|
||||||
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
|
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
|
||||||
Top =
|
Top =
|
||||||
C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
||||||
@@ -107,29 +108,18 @@ class App {
|
|||||||
PD::Gfx::UseDriver<PD::GfxCitro3D>();
|
PD::Gfx::UseDriver<PD::GfxCitro3D>();
|
||||||
#endif
|
#endif
|
||||||
PD::Gfx::Init();
|
PD::Gfx::Init();
|
||||||
PD::Li::InitPools(8192);
|
|
||||||
#ifdef __3DS__
|
#ifdef __3DS__
|
||||||
pTex = LoadTex("sdmc:/icon.png");
|
pTex = LoadTex("sdmc:/icon.png");
|
||||||
#else
|
#else
|
||||||
pTex = LoadTex("icon.png");
|
pTex = LoadTex("icon.png");
|
||||||
#endif
|
#endif
|
||||||
/*std::vector<PD::u8> img(16 * 16 * 4, 0xff);
|
pList.DrawRectFilled(0, 50, 0xff00ffff);
|
||||||
pTex = PD::Gfx::LoadTexture(img, 16, 16);*/
|
pList.BindTexture(pTex);
|
||||||
|
pList.DrawRectFilled(50, pTex.GetSize(), 0xffffffff);
|
||||||
|
pList.DrawCircleFilled(500, 100, 0xffffffff, 50);
|
||||||
|
// pList.PathRect(300, 700, 40.f);
|
||||||
|
// pList.PathFill(0xffffffff);
|
||||||
std::cout << "GfxDriver: " << PD::Gfx::GetDriverName() << std::endl;
|
std::cout << "GfxDriver: " << PD::Gfx::GetDriverName() << std::endl;
|
||||||
pPool.Init(10);
|
|
||||||
auto cmd = pPool.Allocate(1);
|
|
||||||
cmd->Reserve(4, 6);
|
|
||||||
cmd->Add(0, 1, 2);
|
|
||||||
cmd->Add(0, 2, 3);
|
|
||||||
cmd->Add(
|
|
||||||
PD::Li::Vertex(PD::fvec2(0, 0), pTex.GetUV().TopLeft(), 0xffffffff));
|
|
||||||
cmd->Add(PD::Li::Vertex(PD::fvec2(pTex.GetSize().x, 0),
|
|
||||||
pTex.GetUV().TopRight(), 0xffffffff));
|
|
||||||
cmd->Add(PD::Li::Vertex(PD::fvec2(pTex.GetSize().x, pTex.GetSize().y),
|
|
||||||
pTex.GetUV().BotRight(), 0xffffffff));
|
|
||||||
cmd->Add(PD::Li::Vertex(PD::fvec2(0, pTex.GetSize().y),
|
|
||||||
pTex.GetUV().BotLeft(), 0xffffffff));
|
|
||||||
cmd->Tex = pTex.GetID();
|
|
||||||
}
|
}
|
||||||
~App() {
|
~App() {
|
||||||
PD::Gfx::DeleteTexture(pTex);
|
PD::Gfx::DeleteTexture(pTex);
|
||||||
@@ -168,7 +158,7 @@ class App {
|
|||||||
#endif
|
#endif
|
||||||
PD::Gfx::Reset();
|
PD::Gfx::Reset();
|
||||||
|
|
||||||
PD::Gfx::Draw(pPool);
|
PD::Gfx::Draw(pList);
|
||||||
#ifdef __3DS__
|
#ifdef __3DS__
|
||||||
C3D_FrameEnd(0);
|
C3D_FrameEnd(0);
|
||||||
#else
|
#else
|
||||||
@@ -194,7 +184,7 @@ class App {
|
|||||||
#else
|
#else
|
||||||
GLFWwindow* window = nullptr;
|
GLFWwindow* window = nullptr;
|
||||||
#endif
|
#endif
|
||||||
PD::Pool<PD::Li::Command> pPool;
|
PD::Li::Drawlist pList;
|
||||||
PD::Li::Texture pTex;
|
PD::Li::Texture pTex;
|
||||||
Driver pDriver;
|
Driver pDriver;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
2
vendor/spirv-helper
vendored
2
vendor/spirv-helper
vendored
Submodule vendor/spirv-helper updated: 681ab8a8b3...e05a0a45c2
Reference in New Issue
Block a user