Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Aug 6, 2024
1 parent 3a4b9e6 commit a91d9b4
Show file tree
Hide file tree
Showing 8 changed files with 343 additions and 235 deletions.
156 changes: 156 additions & 0 deletions src/libs/karm-gfx/canvas.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <karm-text/font.h>
#include <karm-text/run.h>

#include "canvas.h"

namespace Karm::Gfx {

// MARK: Context Operations ------------------------------------------------

void Canvas::clip(Math::Recti r) {
clip(r.cast<f64>());
}

void Canvas::clip(Math::Rectf r) {
beginPath();
rect(r);
clip();
}

void Canvas::origin(Math::Vec2f p) {
translate(p);
}

void Canvas::translate(Math::Vec2f pos) {
transform(Math::Trans2f::makeTranslate(pos));
}

void Canvas::scale(Math::Vec2f pos) {
transform(Math::Trans2f::makeScale(pos));
}

void Canvas::rotate(f64 angle) {
transform(Math::Trans2f::makeRotate(angle));
}

void Canvas::skew(Math::Vec2f pos) {
transform(Math::Trans2f::makeSkew(pos));
}

// MARK: Path Operations ---------------------------------------------------

void Canvas::fill(Fill style, FillRule rule) {
fillStyle(style);
fill(rule);
}

void Canvas::stroke(Stroke style) {
strokeStyle(style);
stroke();
}

// MARK: Shape Operations ------------------------------------------------------

void Canvas::stroke(Math::Edgef edge) {
// dummy implementation for backends that don't support this operation
beginPath();
moveTo(edge.start);
lineTo(edge.end);
stroke();
}

void Canvas::stroke(Math::Rectf r, Math::Radiif radii) {
// dummy implementation for backends that don't support this operation
beginPath();
rect(r, radii);
stroke();
}

void Canvas::fill(Math::Rectf r, Math::Radiif radii) {
// dummy implementation for backends that don't support this operation
beginPath();
rect(r, radii);
fill();
}

void Canvas::fill(Math::Recti r, Math::Radiii radii) {
rect(r.cast<f64>(), radii.cast<f64>());
fill();
}

void Canvas::stroke(Math::Ellipsef e) {
// dummy implementation for backends that don't support this operation
beginPath();
ellipse(e);
stroke();
}

void Canvas::fill(Math::Ellipsef e) {
// dummy implementation for backends that don't support this operation
beginPath();
ellipse(e);
fill();
}

void Canvas::stroke(Math::Path const &p) {
// dummy implementation for backends that don't support this operation
beginPath();
path(p);
stroke();
}

void Canvas::fill(Math::Path const &p, FillRule rule) {
// dummy implementation for backends that don't support this operation
beginPath();
path(p);
fill(rule);
}

void Canvas::fill(Text::Font &font, Text::Glyph glyph, Math::Vec2f baseline) {
push();
beginPath();
origin(baseline);
scale(font.fontsize);
font.fontface->contour(*this, glyph);
fill();
pop();
}

void Canvas::fill(Text::Font &font, Text::Run const &run, Math::Vec2f baseline) {
push();
for (auto &cell : run._cells)
fill(font, cell.glyph, baseline + Math::Vec2f{cell.xpos, 0});
pop();
}

// MARK: Blit Operations ---------------------------------------------------

void Canvas::blit(Math::Recti dest, Pixels pixels) {
blit(pixels.bound(), dest, pixels);
}

void Canvas::blit(Math::Vec2i dest, Pixels pixels) {
blit(pixels.bound(), Math::Recti(dest, pixels.size()), pixels);
}

// MARK: Filter Operations -------------------------------------------------

void Canvas::apply(Filter filter, Math::Rectf region, Math::Radiif radii) {
beginPath();
rect(region, radii);
apply(filter);
}

void Canvas::apply(Filter filter, Math::Ellipsef region) {
beginPath();
ellipse(region);
apply(filter);
}

void Canvas::apply(Filter filter, Math::Path const &region) {
beginPath();
path(region);
apply(filter);
}

} // namespace Karm::Gfx
141 changes: 138 additions & 3 deletions src/libs/karm-gfx/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,60 @@

#include <karm-math/path.h>
#include <karm-meta/nocopy.h>
#include <karm-text/base.h>

#include "fill.h"
#include "filters.h"
#include "stroke.h"
#include "types.h"

namespace Karm::Gfx {

struct Canvas : public Meta::NoCopy {
// NOTE: Canvas is marked as NoCopy because it doesn't make sense to copy
// a context. And it's also a good way to prevent accidental copies.
// a canvas. And it's also a good way to prevent accidental copies.

Canvas() = default;

Canvas(Canvas &&) = default;
Canvas &operator=(Canvas &&) = default;

virtual ~Canvas() = default;

// MARK: Context Operations ------------------------------------------------

// Push the current context onto the stack.
virtual void push() = 0;

// Pop the current context from the stack.
virtual void pop() = 0;

// Set the current fill style.
virtual void fillStyle(Fill style) = 0;

// Set the current stroke style.
virtual void strokeStyle(Stroke style) = 0;

// Set the origin of the current context.
virtual void origin(Math::Vec2f p);

// Transform subsequent drawing operations using the given matrix.
virtual void transform(Math::Trans2f trans) = 0;

// Translate subsequent drawing operations.
virtual void translate(Math::Vec2f pos);

// Scale subsequent drawing operations.
virtual void scale(Math::Vec2f pos);

// Rotate subsequent drawing operations.
virtual void rotate(f64 angle);

// Skew subsequent drawing operations.
virtual void skew(Math::Vec2f pos);

// MARK: Path Operations ---------------------------------------------------

// Begin a new path.
virtual void beginPath() = 0;

Expand Down Expand Up @@ -55,14 +92,112 @@ struct Canvas : public Meta::NoCopy {
// Add a rectangle to the current path.
virtual void rect(Math::Rectf rect, Math::Radiif radii = 0) = 0;

virtual void path(Math::Path const &path);

// Add an ellipse to the current path.
virtual void ellipse(Math::Ellipsef ellipse) = 0;

// Fill the current path with the given fill.
virtual void fill(Fill fill, FillRule rule = FillRule::NONZERO) = 0;
virtual void fill(FillRule rule = FillRule::NONZERO) = 0;

// Change the current fill style and fill the current path.
virtual void fill(Fill style, FillRule rule = FillRule::NONZERO);

// Stroke the current path with the given style.
virtual void stroke(Stroke style) = 0;
virtual void stroke() = 0;

// Change the current stroke style and stroke the current path.
virtual void stroke(Stroke style);

// Clip the current context to the current path.
virtual void clip() = 0;

// MARK: Shape Operations --------------------------------------------------

// This section defines a set of virtual functions for drawing and filling
// basic shapes (lines, rectangles, ellipses) and complex paths. Each graphics
// backend should provide its own implementation tailored to its technology.

// NOTE: Optimization Strategy
// All functions operate **as if** they clear the current path, start a new one,
// add the shape, and then fill or stroke it. This enables backends to batch
// operations for potential performance gains.

// Stroke a line
virtual void stroke(Math::Edgef edge);

// Stroke a rectangle.
virtual void stroke(Math::Rectf r, Math::Radiif radii = 0);

// Fill a rectangle.
virtual void fill(Math::Rectf r, Math::Radiif radii = 0);

// Fill a rectangle, with integer coordinates.
// NOTE: This is a convenience function for backends that have
// optimized paths for integer coordinates.
virtual void fill(Math::Recti r, Math::Radiii radii = 0);

// Clip the current context to the given rectangle.
virtual void clip(Math::Recti r);

// Clip the current context to the given rectangle.
virtual void clip(Math::Rectf r);

// Stroke an ellipse.
virtual void stroke(Math::Ellipsef e);

// Fill an ellipse.
virtual void fill(Math::Ellipsef e);

// stroke a path
virtual void stroke(Math::Path const &p);

// fill a path
virtual void fill(Math::Path const &p, FillRule rule = FillRule::NONZERO);

// Fill a single glyph of text
virtual void fill(Text::Font &font, Text::Glyph glyph, Math::Vec2f baseline);

// Fill a run of text
virtual void fill(Text::Font &font, Text::Run const &run, Math::Vec2f baseline);

// MARK: Plot Operations ---------------------------------------------------

// Plot a point.
void plot(Math::Vec2i point, Color color);

// Draw a line.
void plot(Math::Edgei edge, Color color);

// Draw a rectangle.
void plot(Math::Recti rect, Color color);

// MARK: Blit Operations ---------------------------------------------------

// Blit the given pixels to the current pixels
// using the given source and destination rectangles.
virtual void blit(Math::Recti src, Math::Recti dest, Pixels pixels) = 0;

// Blit the given pixels to the current pixels.
// The source rectangle is the entire piels.
virtual void blit(Math::Recti dest, Pixels pixels);

// Blit the given pixels to the current pixels at the given position.
virtual void blit(Math::Vec2i dest, Pixels pixels);

// MARK: Filter Operations -------------------------------------------------

// Apply a filter on the given region.
void apply(Filter filter, Math::Rectf region, Math::Radiif radii = 0);

// Apply a filter on the given region.
void apply(Filter filter, Math::Ellipsef region);

// Apply a filter on the given region.
void apply(Filter filter, Math::Path const &region);

// Apply a filter on the current path.
void apply(Filter filter);
};

} // namespace Karm::Gfx
Loading

0 comments on commit a91d9b4

Please sign in to comment.