Implement FillPoly

This commit is contained in:
Oskari Alaranta 2026-02-21 18:05:47 +02:00
parent 4c1f869e32
commit 6119e8dc7a
3 changed files with 90 additions and 8 deletions

View File

@ -2699,6 +2699,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
case X_PolySegment: case X_PolySegment:
TRY(poly_segment(client_info, packet)); TRY(poly_segment(client_info, packet));
break; break;
case X_FillPoly:
TRY(fill_poly(client_info, packet));
break;
case X_PolyFillRectangle: case X_PolyFillRectangle:
TRY(poly_fill_rectangle(client_info, packet)); TRY(poly_fill_rectangle(client_info, packet));
break; break;

View File

@ -3,6 +3,8 @@
#include "SafeGetters.h" #include "SafeGetters.h"
#include "Utils.h" #include "Utils.h"
#include <BAN/Sort.h>
#include <X11/X.h> #include <X11/X.h>
struct DrawSegmentInfo struct DrawSegmentInfo
@ -107,14 +109,15 @@ BAN::ErrorOr<void> poly_line(Client& client_info, BAN::ConstByteSpan packet)
dprintln("PolyLine"); dprintln("PolyLine");
dprintln(" drawable: {}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
dprintln(" coordMode: {}", request.coordMode);
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyLine));
const auto& gc = TRY_REF(get_gc(client_info, request.gc, X_PolyLine));
if (packet.size() < sizeof(xPoint)) if (packet.size() < sizeof(xPoint))
return {}; return {};
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle));
const auto& gc = TRY_REF(get_gc(client_info, request.gc, X_PolyFillRectangle));
DrawSegmentInfo info { DrawSegmentInfo info {
.out_data_u32 = out_data_u32, .out_data_u32 = out_data_u32,
.out_w = out_w, .out_w = out_w,
@ -161,9 +164,9 @@ BAN::ErrorOr<void> poly_segment(Client& client_info, BAN::ConstByteSpan packet)
dprintln(" drawable: {}", request.drawable); dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc); dprintln(" gc: {}", request.gc);
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle)); auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolySegment));
const auto& gc = TRY_REF(get_gc(client_info, request.gc, X_PolyFillRectangle)); const auto& gc = TRY_REF(get_gc(client_info, request.gc, X_PolySegment));
DrawSegmentInfo info { DrawSegmentInfo info {
.out_data_u32 = out_data_u32, .out_data_u32 = out_data_u32,
@ -195,6 +198,81 @@ BAN::ErrorOr<void> poly_segment(Client& client_info, BAN::ConstByteSpan packet)
return {}; return {};
} }
BAN::ErrorOr<void> fill_poly(Client& client_info, BAN::ConstByteSpan packet)
{
auto request = decode<xFillPolyReq>(packet).value();
dprintln("FillPoly");
dprintln(" drawable: {}", request.drawable);
dprintln(" gc: {}", request.gc);
dprintln(" shape: {}", request.shape);
dprintln(" coordMode: {}", request.coordMode);
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_FillPoly));
const auto& gc = TRY_REF(get_gc(client_info, request.gc, X_FillPoly));
if (packet.size() < sizeof(xPoint))
return {};
BAN::Vector<xPoint> points;
TRY(points.push_back(decode<xPoint>(packet).value()));
while (packet.size() >= sizeof(xPoint))
{
auto point = decode<xPoint>(packet).value();
if (request.coordMode == CoordModePrevious)
{
point.x += points.back().x;
point.y += points.back().y;
}
TRY(points.push_back(point));
}
int32_t min_x = INT32_MAX, max_x = INT32_MIN;
int32_t min_y = INT32_MAX, max_y = INT32_MIN;
for (const auto& point : points)
{
min_x = BAN::Math::min<int32_t>(min_x, point.x);
min_y = BAN::Math::min<int32_t>(min_y, point.y);
max_x = BAN::Math::max<int32_t>(max_x, point.x);
max_y = BAN::Math::max<int32_t>(max_y, point.y);
}
for (int32_t y = min_y; y <= max_y; y++)
{
BAN::Vector<float> intersections;
for (size_t i = 0; i < points.size(); i++)
{
const auto& p1 = points[i];
const auto& p2 = points[(i + 1) % points.size()];
if (!(BAN::Math::min(p1.y, p2.y) <= y && y < BAN::Math::max(p1.y, p2.y)))
continue;
const float t = static_cast<float>(y - p1.y) / (p2.y - p1.y);
if (t < 0.0f || t > 1.0f)
continue;
TRY(intersections.push_back(p1.x + (p2.x - p1.x) * t));
}
BAN::sort::sort(intersections.begin(), intersections.end());
for (size_t i = 0; i + 1 < intersections.size(); i += 2)
{
const int32_t lx = BAN::Math::clamp<int32_t>(BAN::Math::ceil (intersections[i + 0]), 0, out_w);
const int32_t rx = BAN::Math::clamp<int32_t>(BAN::Math::floor(intersections[i + 1]), 0, out_w);
for (int32_t x = lx; x <= rx; x++)
if (!gc.is_clipped(x, y))
out_data_u32[y * out_w + x] = gc.foreground;
}
}
if (g_objects[request.drawable]->type == Object::Type::Window)
invalidate_window(request.drawable, min_x, min_y, max_x - min_x + 1, max_y - min_y + 1);
return {};
}
BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan packet) BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan packet)
{ {
auto request = decode<xPolyFillRectangleReq>(packet).value(); auto request = decode<xPolyFillRectangleReq>(packet).value();

View File

@ -4,5 +4,6 @@
BAN::ErrorOr<void> poly_line(Client& client_info, BAN::ConstByteSpan packet); BAN::ErrorOr<void> poly_line(Client& client_info, BAN::ConstByteSpan packet);
BAN::ErrorOr<void> poly_segment(Client& client_info, BAN::ConstByteSpan packet); BAN::ErrorOr<void> poly_segment(Client& client_info, BAN::ConstByteSpan packet);
BAN::ErrorOr<void> fill_poly(Client& client_info, BAN::ConstByteSpan packet);
BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan packet); BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan packet);
BAN::ErrorOr<void> poly_fill_arc(Client& client_info, BAN::ConstByteSpan packet); BAN::ErrorOr<void> poly_fill_arc(Client& client_info, BAN::ConstByteSpan packet);