Add support for rotated gradients
This commit is contained in:
@@ -121,6 +121,20 @@ class PD_API Color {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lerp
|
||||
* @param v Target color
|
||||
* @param t interpolation factor
|
||||
* @return Class Reference
|
||||
*/
|
||||
constexpr Color& Lerp(const Color& v, float t) {
|
||||
a = static_cast<u8>(a + (v.a - a) * t);
|
||||
b = static_cast<u8>(b + (v.b - b) * t);
|
||||
g = static_cast<u8>(g + (v.g - g) * t);
|
||||
r = static_cast<u8>(r + (v.r - r) * t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get 32Bit Color Value
|
||||
* @return 32Bit Color Value (ABGR iirc)
|
||||
|
||||
@@ -26,6 +26,7 @@ using LiDrawFlags = PD::u32;
|
||||
enum LiDrawFlags_ : PD::u32 {
|
||||
LiDrawFlags_None = 0,
|
||||
LiDrawFlags_Close = 1 << 0,
|
||||
LiDrawFlags_AA = 1 << 1,
|
||||
};
|
||||
|
||||
namespace PD {
|
||||
@@ -58,6 +59,8 @@ class PD_API Drawlist {
|
||||
void PathStroke(const PD::Color& color, int t = 1,
|
||||
LiDrawFlags flags = LiDrawFlags_None);
|
||||
void PathFill(const PD::Color& color);
|
||||
void PathFillGradient(const PD::Color& a, const PD::Color& b,
|
||||
float rad = 0.f);
|
||||
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);
|
||||
@@ -97,6 +100,8 @@ class PD_API Drawlist {
|
||||
void DrawPolyLine(const Pool<fvec2>& points, const PD::Color& color,
|
||||
LiDrawFlags flags = LiDrawFlags_None, int t = 1);
|
||||
void DrawConvexPolyFilled(const Pool<fvec2>& points, const PD::Color& color);
|
||||
void DrawConvexPolyFilled(const Pool<fvec2>& points, const PD::Color& a,
|
||||
const PD::Color b, float rad = 0.f);
|
||||
|
||||
void PrimQuad(Command& cmd, const Rect& quad, const Rect& uv,
|
||||
const PD::Color& color);
|
||||
|
||||
@@ -45,6 +45,12 @@ PD_API void Drawlist::PathFill(const PD::Color& color) {
|
||||
PathClear();
|
||||
}
|
||||
|
||||
PD_API void Drawlist::PathFillGradient(const PD::Color& a, const PD::Color& b,
|
||||
float rad) {
|
||||
DrawConvexPolyFilled(pPath, a, b, rad);
|
||||
PathClear();
|
||||
}
|
||||
|
||||
PD_API void Drawlist::PathArcToN(const fvec2& c, float r, float amin,
|
||||
float amax, int s) {
|
||||
// Path.push_back(c);
|
||||
@@ -229,9 +235,9 @@ PD_API void Drawlist::DrawPolyLine(const Pool<fvec2>& points,
|
||||
}
|
||||
UnbindTexture();
|
||||
auto& cmd = NewCommand();
|
||||
bool close = (flags & (1 << 0));
|
||||
bool close = (flags & LiDrawFlags_Close);
|
||||
int num_points = close ? (int)points.size() : (int)points.size() - 1;
|
||||
if (flags & (1 << 1)) {
|
||||
if (flags & LiDrawFlags_AA) {
|
||||
// TODO: Find a way to draw less garbage looking lines
|
||||
} else {
|
||||
// Non antialiased lines look awful when rendering with thickness != 1
|
||||
@@ -282,6 +288,57 @@ PD_API void Drawlist::DrawConvexPolyFilled(const Pool<fvec2>& points,
|
||||
}
|
||||
}
|
||||
|
||||
PD_API void Drawlist::DrawConvexPolyFilled(const Pool<fvec2>& points,
|
||||
const PD::Color& a,
|
||||
const PD::Color b, float rad) {
|
||||
if (points.size() < 3) {
|
||||
return; // Need at least three points
|
||||
}
|
||||
|
||||
fvec2 dir = fvec2(std::cos(rad), std::sin(rad));
|
||||
// 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();
|
||||
|
||||
// Gradient
|
||||
float tmin = std::numeric_limits<float>::max();
|
||||
float tmax = std::numeric_limits<float>::lowest();
|
||||
for (const auto& p : points) {
|
||||
float t = p.x * dir.x + p.y * dir.y;
|
||||
if (t < tmin) tmin = t;
|
||||
if (t > tmax) tmax = t;
|
||||
}
|
||||
// potential div0
|
||||
float irange = (tmax != tmin) ? (1.0f / (tmax - tmin)) : 0.0f;
|
||||
// Command building (oder so)
|
||||
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);
|
||||
}
|
||||
// Why was this for loop not used in normal Convex Poly filled???
|
||||
for (auto& it : points) {
|
||||
// Calculate U and V coords
|
||||
float u = uv_tl.x + ((it.x - minX) / (maxX - minX)) * (uv_tr.x - uv_tl.x);
|
||||
float v = uv_tl.y + ((it.y - minY) / (maxY - minY)) * (uv_bl.y - uv_tl.y);
|
||||
float t = it.x * dir.x + it.y * dir.y;
|
||||
cmd.Add(Vertex(it, fvec2(u, v), PD::Color(a).Lerp(b, (t - tmin) * irange)));
|
||||
}
|
||||
}
|
||||
|
||||
PD_API void Drawlist::PrimQuad(Command& cmd, const Rect& quad, const Rect& uv,
|
||||
const PD::Color& color) {
|
||||
cmd.Reserve(4, 6);
|
||||
|
||||
@@ -58,6 +58,7 @@ 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();
|
||||
if (len == 0.0f) return Rect();
|
||||
vec2 unit_dir = dir / len;
|
||||
vec2 perpendicular(-unit_dir.y, unit_dir.x);
|
||||
vec2 off = perpendicular * ((float)t * 0.5f);
|
||||
|
||||
@@ -166,6 +166,52 @@ struct Cursor {
|
||||
}
|
||||
};
|
||||
|
||||
void DrawRectGradient135(PD::Li::Drawlist& l, const PD::fvec2& pos,
|
||||
const PD::fvec2& size, const PD::Color& colA,
|
||||
const PD::Color& colB) {
|
||||
PD::fvec2 p0 = pos;
|
||||
PD::fvec2 p1 = PD::fvec2(pos.x + size.x, pos.y);
|
||||
PD::fvec2 p2 = PD::fvec2(pos.x + size.x, pos.y + size.y);
|
||||
PD::fvec2 p3 = PD::fvec2(pos.x, pos.y + size.y);
|
||||
|
||||
// 135° direction
|
||||
PD::fvec2 dir = PD::fvec2(-0.70710678f, 0.70710678f);
|
||||
|
||||
// Project all corners
|
||||
float t0 = p0.x * dir.x + p0.y * dir.y;
|
||||
float t1 = p1.x * dir.x + p1.y * dir.y;
|
||||
float t2 = p2.x * dir.x + p2.y * dir.y;
|
||||
float t3 = p3.x * dir.x + p3.y * dir.y;
|
||||
|
||||
float tmin = std::min({t0, t1, t2, t3});
|
||||
float tmax = std::max({t0, t1, t2, t3});
|
||||
|
||||
auto normalize = [&](float t) { return (t - tmin) / (tmax - tmin); };
|
||||
|
||||
auto lerpColor = [&](float t) {
|
||||
return PD::Color(colA.rf() + (colB.rf() - colA.rf()) * t,
|
||||
colA.gf() + (colB.gf() - colA.gf()) * t,
|
||||
colA.bf() + (colB.bf() - colA.bf()) * t,
|
||||
colA.af() + (colB.af() - colA.af()) * t);
|
||||
};
|
||||
|
||||
PD::Color c0 = lerpColor(normalize(t0));
|
||||
PD::Color c1 = lerpColor(normalize(t1));
|
||||
PD::Color c2 = lerpColor(normalize(t2));
|
||||
PD::Color c3 = lerpColor(normalize(t3));
|
||||
|
||||
auto& cmd = l.NewCommand();
|
||||
cmd.Reserve(4, 6);
|
||||
|
||||
cmd.Add(2, 1, 0);
|
||||
cmd.Add(3, 2, 0);
|
||||
|
||||
cmd.Add(PD::Li::Vertex(p0, PD::fvec2(0, 0), c0));
|
||||
cmd.Add(PD::Li::Vertex(p1, PD::fvec2(1, 0), c1));
|
||||
cmd.Add(PD::Li::Vertex(p2, PD::fvec2(1, 1), c2));
|
||||
cmd.Add(PD::Li::Vertex(p3, PD::fvec2(0, 1), c3));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// PD::LogFilter(PD::LogLevel::Warning);
|
||||
Driver drv = Driver::OpenGL3;
|
||||
@@ -252,6 +298,17 @@ int main(int argc, char** argv) {
|
||||
"#ffffff");
|
||||
LeftStick.Render(pList);
|
||||
RightStick.Render(pList);
|
||||
pList.UnbindTexture();
|
||||
pList.PathRect(50, PD::fvec2(450, 240));
|
||||
pList.PathFillGradient("#ff0000", "#990000", PD::Radians(135));
|
||||
pList.PathAdd(PD::fvec2(100, 120));
|
||||
pList.PathAdd(PD::fvec2(250, 260));
|
||||
pList.PathAdd(PD::fvec2(420, 180));
|
||||
pList.PathAdd(PD::fvec2(600, 320));
|
||||
pList.PathAdd(PD::fvec2(820, 220));
|
||||
pList.PathAdd(PD::fvec2(1000, 360));
|
||||
|
||||
pList.PathStroke("#ff00ff", 10, LiDrawFlags_AA);
|
||||
PD::Gfx::Reset();
|
||||
PD::Gfx::Draw(pList);
|
||||
pList.Clear();
|
||||
|
||||
Reference in New Issue
Block a user