mirror of
				https://github.com/RetroDECK/ES-DE.git
				synced 2025-04-10 19:15:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			262 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "canvas.h"
 | |
| 
 | |
| #include <cmath>
 | |
| 
 | |
| namespace lunasvg {
 | |
| 
 | |
| static plutovg_matrix_t to_plutovg_matrix(const Transform& transform);
 | |
| static plutovg_fill_rule_t to_plutovg_fill_rule(WindRule winding);
 | |
| static plutovg_operator_t to_plutovg_operator(BlendMode mode);
 | |
| static plutovg_line_cap_t to_plutovg_line_cap(LineCap cap);
 | |
| static plutovg_line_join_t to_plutovg_line_join(LineJoin join);
 | |
| static plutovg_spread_method_t to_plutovg_spread_method(SpreadMethod spread);
 | |
| static plutovg_texture_type_t to_plutovg_texture_type(TextureType type);
 | |
| static void to_plutovg_stops(plutovg_gradient_t* gradient, const GradientStops& stops);
 | |
| static void to_plutovg_path(plutovg_t* pluto, const Path& path);
 | |
| 
 | |
| std::shared_ptr<Canvas> Canvas::create(unsigned char* data, unsigned int width, unsigned int height, unsigned int stride)
 | |
| {
 | |
|     return std::shared_ptr<Canvas>(new Canvas(data, static_cast<int>(width), static_cast<int>(height), static_cast<int>(stride)));
 | |
| }
 | |
| 
 | |
| std::shared_ptr<Canvas> Canvas::create(double x, double y, double width, double height)
 | |
| {
 | |
|     if(width <= 0.0 || height <= 0.0)
 | |
|         return std::shared_ptr<Canvas>(new Canvas(0, 0, 1, 1));
 | |
| 
 | |
|     auto l = static_cast<int>(floor(x));
 | |
|     auto t = static_cast<int>(floor(y));
 | |
|     auto r = static_cast<int>(ceil(x + width));
 | |
|     auto b = static_cast<int>(ceil(y + height));
 | |
|     return std::shared_ptr<Canvas>(new Canvas(l, t, r - l, b - t));
 | |
| }
 | |
| 
 | |
| std::shared_ptr<Canvas> Canvas::create(const Rect& box)
 | |
| {
 | |
|     return create(box.x, box.y, box.w, box.h);
 | |
| }
 | |
| 
 | |
| Canvas::Canvas(unsigned char* data, int width, int height, int stride)
 | |
| {
 | |
|     surface = plutovg_surface_create_for_data(data, width, height, stride);
 | |
|     pluto = plutovg_create(surface);
 | |
|     plutovg_matrix_init_identity(&translation);
 | |
|     plutovg_rect_init(&rect, 0, 0, width, height);
 | |
| }
 | |
| 
 | |
| Canvas::Canvas(int x, int y, int width, int height)
 | |
| {
 | |
|     surface = plutovg_surface_create(width, height);
 | |
|     pluto = plutovg_create(surface);
 | |
|     plutovg_matrix_init_translate(&translation, -x, -y);
 | |
|     plutovg_rect_init(&rect, x, y, width, height);
 | |
| }
 | |
| 
 | |
| Canvas::~Canvas()
 | |
| {
 | |
|     plutovg_surface_destroy(surface);
 | |
|     plutovg_destroy(pluto);
 | |
| }
 | |
| 
 | |
| void Canvas::setColor(const Color& color)
 | |
| {
 | |
|     plutovg_set_rgba(pluto, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0);
 | |
| }
 | |
| 
 | |
| void Canvas::setLinearGradient(double x1, double y1, double x2, double y2, const GradientStops& stops, SpreadMethod spread, const Transform& transform)
 | |
| {
 | |
|     auto gradient = plutovg_set_linear_gradient(pluto, x1, y1, x2, y2);
 | |
|     auto matrix = to_plutovg_matrix(transform);
 | |
|     to_plutovg_stops(gradient, stops);
 | |
|     plutovg_gradient_set_spread(gradient, to_plutovg_spread_method(spread));
 | |
|     plutovg_gradient_set_matrix(gradient, &matrix);
 | |
| }
 | |
| 
 | |
| void Canvas::setRadialGradient(double cx, double cy, double r, double fx, double fy, const GradientStops& stops, SpreadMethod spread, const Transform& transform)
 | |
| {
 | |
|     auto gradient = plutovg_set_radial_gradient(pluto, cx, cy, r, fx, fy, 0);
 | |
|     auto matrix = to_plutovg_matrix(transform);
 | |
|     to_plutovg_stops(gradient, stops);
 | |
|     plutovg_gradient_set_spread(gradient, to_plutovg_spread_method(spread));
 | |
|     plutovg_gradient_set_matrix(gradient, &matrix);
 | |
| }
 | |
| 
 | |
| void Canvas::setTexture(const Canvas* source, TextureType type, const Transform& transform)
 | |
| {
 | |
|     auto texture = plutovg_set_texture(pluto, source->surface, to_plutovg_texture_type(type));
 | |
|     auto matrix = to_plutovg_matrix(transform);
 | |
|     plutovg_texture_set_matrix(texture, &matrix);
 | |
| }
 | |
| 
 | |
| void Canvas::fill(const Path& path, const Transform& transform, WindRule winding, BlendMode mode, double opacity)
 | |
| {
 | |
|     auto matrix = to_plutovg_matrix(transform);
 | |
|     plutovg_matrix_multiply(&matrix, &matrix, &translation);
 | |
|     to_plutovg_path(pluto, path);
 | |
|     plutovg_set_matrix(pluto, &matrix);
 | |
|     plutovg_set_fill_rule(pluto, to_plutovg_fill_rule(winding));
 | |
|     plutovg_set_opacity(pluto, opacity);
 | |
|     plutovg_set_operator(pluto, to_plutovg_operator(mode));
 | |
|     plutovg_fill(pluto);
 | |
| }
 | |
| 
 | |
| void Canvas::stroke(const Path& path, const Transform& transform, double width, LineCap cap, LineJoin join, double miterlimit, const DashData& dash, BlendMode mode, double opacity)
 | |
| {
 | |
|     auto matrix = to_plutovg_matrix(transform);
 | |
|     plutovg_matrix_multiply(&matrix, &matrix, &translation);
 | |
|     to_plutovg_path(pluto, path);
 | |
|     plutovg_set_matrix(pluto, &matrix);
 | |
|     plutovg_set_line_width(pluto, width);
 | |
|     plutovg_set_line_cap(pluto, to_plutovg_line_cap(cap));
 | |
|     plutovg_set_line_join(pluto, to_plutovg_line_join(join));
 | |
|     plutovg_set_miter_limit(pluto, miterlimit);
 | |
|     plutovg_set_dash(pluto, dash.offset, dash.array.data(), static_cast<int>(dash.array.size()));
 | |
|     plutovg_set_operator(pluto, to_plutovg_operator(mode));
 | |
|     plutovg_set_opacity(pluto, opacity);
 | |
|     plutovg_stroke(pluto);
 | |
| }
 | |
| 
 | |
| void Canvas::blend(const Canvas* source, BlendMode mode, double opacity)
 | |
| {
 | |
|     plutovg_set_texture_surface(pluto, source->surface, source->rect.x, source->rect.y);
 | |
|     plutovg_set_operator(pluto, to_plutovg_operator(mode));
 | |
|     plutovg_set_opacity(pluto, opacity);
 | |
|     plutovg_set_matrix(pluto, &translation);
 | |
|     plutovg_paint(pluto);
 | |
| }
 | |
| 
 | |
| void Canvas::mask(const Rect& clip, const Transform& transform)
 | |
| {
 | |
|     auto matrix = to_plutovg_matrix(transform);
 | |
|     auto path = plutovg_path_create();
 | |
|     plutovg_path_add_rect(path, clip.x, clip.y, clip.w, clip.h);
 | |
|     plutovg_path_transform(path, &matrix);
 | |
|     plutovg_rect(pluto, rect.x, rect.y, rect.w, rect.h);
 | |
|     plutovg_add_path(pluto, path);
 | |
|     plutovg_path_destroy(path);
 | |
| 
 | |
|     plutovg_set_rgba(pluto, 0, 0, 0, 0);
 | |
|     plutovg_set_fill_rule(pluto, plutovg_fill_rule_even_odd);
 | |
|     plutovg_set_operator(pluto, plutovg_operator_src);
 | |
|     plutovg_set_opacity(pluto, 0.0);
 | |
|     plutovg_set_matrix(pluto, &translation);
 | |
|     plutovg_fill(pluto);
 | |
| }
 | |
| 
 | |
| void Canvas::luminance()
 | |
| {
 | |
|     auto width = plutovg_surface_get_width(surface);
 | |
|     auto height = plutovg_surface_get_height(surface);
 | |
|     auto stride = plutovg_surface_get_stride(surface);
 | |
|     auto data = plutovg_surface_get_data(surface);
 | |
|     for(int y = 0; y < height; y++) {
 | |
|         auto pixels = reinterpret_cast<uint32_t*>(data + stride * y);
 | |
|         for(int x = 0; x < width; x++) {
 | |
|             auto pixel = pixels[x];
 | |
|             auto r = (pixel >> 16) & 0xFF;
 | |
|             auto g = (pixel >> 8) & 0xFF;
 | |
|             auto b = (pixel >> 0) & 0xFF;
 | |
|             auto l = (2*r + 3*g + b) / 6;
 | |
| 
 | |
|             pixels[x] = l << 24;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| unsigned int Canvas::width() const
 | |
| {
 | |
|     return plutovg_surface_get_width(surface);
 | |
| }
 | |
| 
 | |
| unsigned int Canvas::height() const
 | |
| {
 | |
|     return plutovg_surface_get_height(surface);
 | |
| }
 | |
| 
 | |
| unsigned int Canvas::stride() const
 | |
| {
 | |
|     return plutovg_surface_get_stride(surface);
 | |
| }
 | |
| 
 | |
| unsigned char* Canvas::data() const
 | |
| {
 | |
|     return plutovg_surface_get_data(surface);
 | |
| }
 | |
| 
 | |
| Rect Canvas::box() const
 | |
| {
 | |
|     return Rect(rect.x, rect.y, rect.w, rect.h);
 | |
| }
 | |
| 
 | |
| plutovg_matrix_t to_plutovg_matrix(const Transform& transform)
 | |
| {
 | |
|     plutovg_matrix_t matrix;
 | |
|     plutovg_matrix_init(&matrix, transform.m00, transform.m10, transform.m01, transform.m11, transform.m02, transform.m12);
 | |
|     return matrix;
 | |
| }
 | |
| 
 | |
| plutovg_fill_rule_t to_plutovg_fill_rule(WindRule winding)
 | |
| {
 | |
|     return winding == WindRule::EvenOdd ? plutovg_fill_rule_even_odd : plutovg_fill_rule_non_zero;
 | |
| }
 | |
| 
 | |
| plutovg_operator_t to_plutovg_operator(BlendMode mode)
 | |
| {
 | |
|     return mode == BlendMode::Src ? plutovg_operator_src : mode == BlendMode::Src_Over ? plutovg_operator_src_over : mode == BlendMode::Dst_In ? plutovg_operator_dst_in : plutovg_operator_dst_out;
 | |
| }
 | |
| 
 | |
| plutovg_line_cap_t to_plutovg_line_cap(LineCap cap)
 | |
| {
 | |
|     return cap == LineCap::Butt ? plutovg_line_cap_butt : cap == LineCap::Round ? plutovg_line_cap_round : plutovg_line_cap_square;
 | |
| }
 | |
| 
 | |
| plutovg_line_join_t to_plutovg_line_join(LineJoin join)
 | |
| {
 | |
|     return join == LineJoin::Miter ? plutovg_line_join_miter : join == LineJoin::Round ? plutovg_line_join_round : plutovg_line_join_bevel;
 | |
| }
 | |
| 
 | |
| static plutovg_spread_method_t to_plutovg_spread_method(SpreadMethod spread)
 | |
| {
 | |
|     return spread == SpreadMethod::Pad ? plutovg_spread_method_pad : spread == SpreadMethod::Reflect ? plutovg_spread_method_reflect : plutovg_spread_method_repeat;
 | |
| }
 | |
| 
 | |
| static plutovg_texture_type_t to_plutovg_texture_type(TextureType type)
 | |
| {
 | |
|     return type == TextureType::Plain ? plutovg_texture_type_plain : plutovg_texture_type_tiled;
 | |
| }
 | |
| 
 | |
| static void to_plutovg_stops(plutovg_gradient_t* gradient, const GradientStops& stops)
 | |
| {
 | |
|     for(const auto& stop : stops) {
 | |
|         auto offset = std::get<0>(stop);
 | |
|         auto& color = std::get<1>(stop);
 | |
|         plutovg_gradient_add_stop_rgba(gradient, offset, color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0, color.alpha() / 255.0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void to_plutovg_path(plutovg_t* pluto, const Path& path)
 | |
| {
 | |
|     PathIterator it(path);
 | |
|     std::array<Point, 3> p;
 | |
|     while(!it.isDone()) {
 | |
|         switch(it.currentSegment(p)) {
 | |
|         case PathCommand::MoveTo:
 | |
|             plutovg_move_to(pluto, p[0].x, p[0].y);
 | |
|             break;
 | |
|         case PathCommand::LineTo:
 | |
|             plutovg_line_to(pluto, p[0].x, p[0].y);
 | |
|             break;
 | |
|         case PathCommand::CubicTo:
 | |
|             plutovg_cubic_to(pluto, p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y);
 | |
|             break;
 | |
|         case PathCommand::Close:
 | |
|             plutovg_close_path(pluto);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         it.next();
 | |
|     }
 | |
| }
 | |
| 
 | |
| } // namespace lunasvg
 | 
