Skip to content

Commit

Permalink
feat: add circle funcs
Browse files Browse the repository at this point in the history
Signed-off-by: LingSamuel <[email protected]>
  • Loading branch information
lingsamuel committed Nov 26, 2024
1 parent 391599d commit 1058bef
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 1 deletion.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,27 @@ function()

-- Draw image at the bottom left corner of the screen but scaled to 50x50.
d2d.image(image, 0, screen_h - 50, 50, 50)

-- x, y, width, height, corner round x, corner round y, thickness, color
d2d.rounded_rect(400, 500, 80, 40, 5, 15, 5, 0xFF00FFFF)
-- x, y, width, height, corner round x, corner round y, color
d2d.fill_rounded_rect(400, 500, 80, 40, 5, 15, 0xFF00FFFF)

-- x, y, radius x, radius y, color
d2d.fill_circle(600, 500, 50, 50, 0xFF00FFFF)
d2d.fill_circle(700, 500, 50, 80, 0xFF00FFFF)

-- x, y, radius x, radius y, thickness, color
d2d.circle(800, 500, 50, 50, 5, 0xFF00FFFF)
d2d.circle(900, 500, 50, 80, 5, 0xFF00FFFF)

-- x, y, radius, start angle, sweep angle, color
d2d.pie(1000, 500, 50, 0, 240, 0xFF00FFFF)
d2d.pie(1100, 500, 50, 60, 240, 0xFF00FFFF)

-- x, y, outer radius, inner radius, start angle, sweep angle, color
d2d.ring(1200, 500, 50, 30, 0, 240, 0xFF00FFFF)
d2d.ring(1300, 500, 50, 30, 60, 240, 0xFF00FFFF)
end)
```

Expand Down
144 changes: 144 additions & 0 deletions src/D2DPainter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ void D2DPainter::outline_rect(float x, float y, float w, float h, float thicknes
m_context->DrawRectangle({x, y, x + w, y + h}, m_brush.Get(), thickness);
}

void D2DPainter::rounded_rect(float x, float y, float w, float h, float radiusX, float radiusY, float thickness, unsigned int color) {
set_color(color);
m_context->DrawRoundedRectangle({x, y, x + w, y + h, radiusX, radiusY}, m_brush.Get(), thickness);
}

void D2DPainter::fill_rounded_rect(float x, float y, float w, float h, float radiusX, float radiusY, unsigned int color) {
set_color(color);
m_context->FillRoundedRectangle({x, y, x + w, y + h, radiusX, radiusY}, m_brush.Get());
}

void D2DPainter::line(float x1, float y1, float x2, float y2, float thickness, unsigned int color) {
set_color(color);
m_context->DrawLine({x1, y1}, {x2, y2}, m_brush.Get(), thickness);
Expand All @@ -90,3 +100,137 @@ void D2DPainter::image(std::shared_ptr<D2DImage>& image, float x, float y) {
void D2DPainter::image(std::shared_ptr<D2DImage>& image, float x, float y, float w, float h) {
m_context->DrawBitmap(image->bitmap().Get(), {x, y, x + w, y + h});
}

void D2DPainter::fill_circle(float centerX, float centerY, float radius, unsigned int color) {
set_color(color);
D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(centerX, centerY), radius, radius);
m_context->FillEllipse(ellipse, m_brush.Get());
}

void D2DPainter::fill_circle(float centerX, float centerY, float radiusX, float radiusY, unsigned int color) {
set_color(color);
D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(centerX, centerY), radiusX, radiusY);
m_context->FillEllipse(ellipse, m_brush.Get());
}

void D2DPainter::circle(float centerX, float centerY, float radius, int thickness, unsigned int color) {
set_color(color);
D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(centerX, centerY), radius, radius);
m_context->DrawEllipse(ellipse, m_brush.Get(), thickness);
}

void D2DPainter::circle(float centerX, float centerY, float radiusX, float radiusY, int thickness, unsigned int color) {
set_color(color);
D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(centerX, centerY), radiusX, radiusY);
m_context->DrawEllipse(ellipse, m_brush.Get(), thickness);
}

void D2DPainter::pie(float centerX, float centerY, float radius, float startAngle, float sweepAngle, unsigned int color) {
startAngle = std::clamp(startAngle, 0.0f, 360.0f);
sweepAngle = std::clamp(sweepAngle, 0.0f, 360.0f);
if (sweepAngle == 0.0f) {
return;
}
if (sweepAngle == 360.0f) {
return this->fill_circle(centerX, centerY, radius, color);
}

ComPtr<ID2D1PathGeometry> pathGeometry;
m_d2d1->CreatePathGeometry(&pathGeometry);

ComPtr<ID2D1GeometrySink> geometrySink;
pathGeometry->Open(&geometrySink);

const float startRadians = startAngle * (3.14159265f / 180.0f);
const float endRadians = (startAngle + sweepAngle) * (3.14159265f / 180.0f);

D2D1_POINT_2F circleCenter = D2D1::Point2F(centerX, centerY);

// circle center -> arc start
D2D1_POINT_2F arcStart = D2D1::Point2F(centerX + radius * cosf(startRadians), centerY + radius * sinf(startRadians));
geometrySink->BeginFigure(circleCenter, D2D1_FIGURE_BEGIN_FILLED);
geometrySink->AddLine(arcStart);

// arc start -> arc end
D2D1_POINT_2F arcEnd = D2D1::Point2F(centerX + radius * cosf(endRadians), centerY + radius * sinf(endRadians));
geometrySink->AddArc(D2D1::ArcSegment(arcEnd, D2D1::SizeF(radius, radius), 0.0f, D2D1_SWEEP_DIRECTION_CLOCKWISE,
(sweepAngle > 180.0f) ? D2D1_ARC_SIZE_LARGE : D2D1_ARC_SIZE_SMALL));

// arc end -> circle center
geometrySink->AddLine(circleCenter);

// end
geometrySink->EndFigure(D2D1_FIGURE_END_CLOSED);
geometrySink->Close();

set_color(color);
m_context->FillGeometry(pathGeometry.Get(), m_brush.Get());
}

void D2DPainter::ring(float centerX, float centerY, float outerRadius, float innerRadius, unsigned int color) {
ComPtr<ID2D1EllipseGeometry> outerCircle;
m_d2d1->CreateEllipseGeometry(D2D1::Ellipse(D2D1::Point2F(centerX, centerY), outerRadius, outerRadius), &outerCircle);
ComPtr<ID2D1EllipseGeometry> innerCircle;
m_d2d1->CreateEllipseGeometry(D2D1::Ellipse(D2D1::Point2F(centerX, centerY), innerRadius, innerRadius), &innerCircle);

ComPtr<ID2D1PathGeometry> pathGeometry;
m_d2d1->CreatePathGeometry(&pathGeometry);
ComPtr<ID2D1GeometrySink> sink;
pathGeometry->Open(&sink);

outerCircle->CombineWithGeometry(innerCircle.Get(), D2D1_COMBINE_MODE_EXCLUDE, NULL, sink.Get());
sink->Close();

set_color(color);
m_context->FillGeometry(pathGeometry.Get(), m_brush.Get());
}

void D2DPainter::ring(float centerX, float centerY, float outerRadius, float innerRadius, float startAngle, float sweepAngle, unsigned int color) {
startAngle = std::clamp(startAngle, 0.0f, 360.0f);
sweepAngle = std::clamp(sweepAngle, 0.0f, 360.0f);
if (sweepAngle == 0.0f) {
return;
}
if (sweepAngle == 360.0f) {
return this->ring(centerX, centerY, outerRadius, innerRadius, color);
}

set_color(color);

ComPtr<ID2D1PathGeometry> pathGeometry;
m_d2d1->CreatePathGeometry(&pathGeometry);

ComPtr<ID2D1GeometrySink> sink;
pathGeometry->Open(&sink);

const float startRadians = startAngle * (3.14159265f / 180.0f);
const float endRadians = (startAngle + sweepAngle) * (3.14159265f / 180.0f);

// outer arc start
D2D1_POINT_2F outerStart = D2D1::Point2F(centerX + outerRadius * std::cos(startRadians), centerY + outerRadius * std::sin(startRadians));
sink->BeginFigure(outerStart, D2D1_FIGURE_BEGIN_FILLED);

// outer arc start -> outer arc end
D2D1_POINT_2F outerEnd = D2D1::Point2F(centerX + outerRadius * std::cos(endRadians), centerY + outerRadius * std::sin(endRadians));
sink->AddArc(D2D1::ArcSegment(outerEnd, D2D1::SizeF(outerRadius, outerRadius), 0.0f, D2D1_SWEEP_DIRECTION_CLOCKWISE,
(sweepAngle > 180.0f) ? D2D1_ARC_SIZE_LARGE : D2D1_ARC_SIZE_SMALL));

// outer arc end -> inner arc end
D2D1_POINT_2F innerEnd = D2D1::Point2F(centerX + innerRadius * std::cos(endRadians), centerY + innerRadius * std::sin(endRadians));
sink->AddLine(innerEnd);

// inner arc end -> inner arc start
D2D1_POINT_2F innerStart = D2D1::Point2F(centerX + innerRadius * std::cos(startRadians), centerY + innerRadius * std::sin(startRadians));
sink->AddArc(D2D1::ArcSegment(innerStart, D2D1::SizeF(innerRadius, innerRadius), 0.0f, D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
(sweepAngle > 180.0f) ? D2D1_ARC_SIZE_LARGE : D2D1_ARC_SIZE_SMALL));

// inner arc start -> outer arc start
sink->AddLine(outerStart);

// end
sink->EndFigure(D2D1_FIGURE_END_CLOSED);
sink->Close();

set_color(color);
m_context->FillGeometry(pathGeometry.Get(), m_brush.Get());
}
9 changes: 9 additions & 0 deletions src/D2DPainter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ class D2DPainter {
void text(std::shared_ptr<D2DFont>& font, const std::string& text, float x, float y, unsigned int color);
void fill_rect(float x, float y, float w, float h, unsigned int color);
void outline_rect(float x, float y, float w, float h, float thickness, unsigned int color);
void rounded_rect(float x, float y, float w, float h, float radiusX, float radiusY, float thickness, unsigned int color);
void fill_rounded_rect(float x, float y, float w, float h, float radiusX, float radiusY, unsigned int color);
void line(float x1, float y1, float x2, float y2, float thickness, unsigned int color);
void image(std::shared_ptr<D2DImage>& image, float x, float y);
void image(std::shared_ptr<D2DImage>& image, float x, float y, float w, float h);
void fill_circle(float centerX, float centerY, float radius, unsigned int color);
void fill_circle(float centerX, float centerY, float radiusX, float radiusY, unsigned int color);
void circle(float centerX, float centerY, float radius, int thickness, unsigned int color);
void circle(float centerX, float centerY, float radiusX, float radiusY, int thickness, unsigned int color);
void pie(float centerX, float centerY, float radius, float startAngle, float sweepAngle, unsigned int color);
void ring(float centerX, float centerY, float outerRadius, float innerRadius, unsigned int color);
void ring(float centerX, float centerY, float outerRadius, float innerRadius, float startAngle, float sweepAngle, unsigned int color);

auto surface_size() const { return std::make_tuple(m_rt_desc.Width, m_rt_desc.Height); }

Expand Down
75 changes: 75 additions & 0 deletions src/DrawList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ void DrawList::CommandLock::outline_rect(float x, float y, float w, float h, flo
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::rounded_rect(float x, float y, float w, float h, float rX, float rY, float thickness, unsigned int color) {
Command cmd{};
cmd.type = CommandType::ROUNDED_RECT;
cmd.rounded_rect.x = x;
cmd.rounded_rect.y = y;
cmd.rounded_rect.w = w;
cmd.rounded_rect.h = h;
cmd.rounded_rect.rX = rX;
cmd.rounded_rect.rY = rY;
cmd.rounded_rect.thickness = thickness;
cmd.rounded_rect.color = color;
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::fill_rounded_rect(float x, float y, float w, float h, float rX, float rY, unsigned int color) {
Command cmd{};
cmd.type = CommandType::FILL_ROUNDED_RECT;
cmd.rounded_rect.x = x;
cmd.rounded_rect.y = y;
cmd.rounded_rect.w = w;
cmd.rounded_rect.h = h;
cmd.rounded_rect.rX = rX;
cmd.rounded_rect.rY = rY;
cmd.rounded_rect.color = color;
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::line(float x1, float y1, float x2, float y2, float thickness, unsigned int color) {
Command cmd{};
cmd.type = CommandType::LINE;
Expand All @@ -56,3 +83,51 @@ void DrawList::CommandLock::image(std::shared_ptr<D2DImage>& image, float x, flo
cmd.image_resource = image;
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::fill_circle(float x, float y, float radiusX, float radiusY, unsigned int color) {
Command cmd{};
cmd.type = CommandType::FILL_CIRCLE;
cmd.fill_circle.x = x;
cmd.fill_circle.y = y;
cmd.fill_circle.radiusX = radiusX;
cmd.fill_circle.radiusY = radiusY;
cmd.fill_circle.color = color;
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::circle(float x, float y, float radiusX, float radiusY, float thickness, unsigned int color) {
Command cmd{};
cmd.type = CommandType::CIRCLE;
cmd.circle.x = x;
cmd.circle.y = y;
cmd.circle.radiusX = radiusX;
cmd.circle.radiusY = radiusY;
cmd.circle.thickness = thickness;
cmd.circle.color = color;
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::pie(float x, float y, float r, float startAngle, float sweepAngle, unsigned int color) {
Command cmd{};
cmd.type = CommandType::PIE;
cmd.pie.x = x;
cmd.pie.y = y;
cmd.pie.r = r;
cmd.pie.startAngle = startAngle;
cmd.pie.sweepAngle = sweepAngle;
cmd.pie.color = color;
commands.emplace_back(std::move(cmd));
}

void DrawList::CommandLock::ring(float x, float y, float outerRadius, float innerRadius, float startAngle, float sweepAngle, unsigned int color) {
Command cmd{};
cmd.type = CommandType::RING;
cmd.ring.x = x;
cmd.ring.y = y;
cmd.ring.outerRadius = outerRadius;
cmd.ring.innerRadius = innerRadius;
cmd.ring.startAngle = startAngle;
cmd.ring.sweepAngle = sweepAngle;
cmd.ring.color = color;
commands.emplace_back(std::move(cmd));
}
59 changes: 58 additions & 1 deletion src/DrawList.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class DrawList {
public:
enum class CommandType { TEXT, FILL_RECT, OUTLINE_RECT, LINE, IMAGE };
enum class CommandType { TEXT, FILL_RECT, OUTLINE_RECT, ROUNDED_RECT, FILL_ROUNDED_RECT, LINE, IMAGE, FILL_CIRCLE, CIRCLE, PIE, RING };

struct Command {
CommandType type;
Expand All @@ -35,6 +35,25 @@ class DrawList {
float thickness{};
unsigned int color{};
} outline_rect;
struct {
float x{};
float y{};
float w{};
float h{};
float rX{};
float rY{};
float thickness{};
unsigned int color{};
} rounded_rect;
struct {
float x{};
float y{};
float w{};
float h{};
float rX{};
float rY{};
unsigned int color{};
} fill_rounded_rect;
struct {
float x1{};
float y1{};
Expand All @@ -49,6 +68,38 @@ class DrawList {
float w{};
float h{};
} image;
struct {
float x{};
float y{};
float radiusX{};
float radiusY{};
unsigned int color{};
} fill_circle;
struct {
float x{};
float y{};
float radiusX{};
float radiusY{};
float thickness{};
unsigned int color{};
} circle;
struct {
float x{};
float y{};
float r{};
float startAngle{};
float sweepAngle{};
unsigned int color{};
} pie;
struct {
float x{};
float y{};
float outerRadius{};
float innerRadius{};
float startAngle{};
float sweepAngle{};
unsigned int color{};
} ring;
};
std::string str{};
std::shared_ptr<D2DFont> font_resource{};
Expand All @@ -62,8 +113,14 @@ class DrawList {
void text(std::shared_ptr<D2DFont>& font, std::string text, float x, float y, unsigned int color);
void fill_rect(float x, float y, float w, float h, unsigned int color);
void outline_rect(float x, float y, float w, float h, float thickness, unsigned int color);
void rounded_rect(float x, float y, float w, float h, float rX, float rY, float thickness, unsigned int color);
void fill_rounded_rect(float x, float y, float w, float h, float rX, float rY, unsigned int color);
void line(float x1, float y1, float x2, float y2, float thickness, unsigned int color);
void image(std::shared_ptr<D2DImage>& image, float x, float y, float w, float h);
void fill_circle(float x, float y, float radiusX, float radiusY, unsigned int color);
void circle(float x, float y, float radiusX, float radiusY, float thickness, unsigned int color);
void pie(float x, float y, float r, float startAngle, float sweepAngle, unsigned int color);
void ring(float x, float y, float outerRadius, float innerRadius, float startAngle, float sweepAngle, unsigned int color);
};

auto acquire() { return CommandLock{m_commands, std::scoped_lock{m_commands_mux}}; }
Expand Down
Loading

0 comments on commit 1058bef

Please sign in to comment.