Files
pcsx2/3rdparty/plutosvg/plutovg/source/plutovg-matrix.c
2025-11-18 14:18:26 -07:00

232 lines
7.4 KiB
C

#include "plutovg.h"
#include "plutovg-utils.h"
void plutovg_matrix_init(plutovg_matrix_t* matrix, float a, float b, float c, float d, float e, float f)
{
matrix->a = a; matrix->b = b;
matrix->c = c; matrix->d = d;
matrix->e = e; matrix->f = f;
}
void plutovg_matrix_init_identity(plutovg_matrix_t* matrix)
{
matrix->a = 1; matrix->b = 0;
matrix->c = 0; matrix->d = 1;
matrix->e = 0; matrix->f = 0;
}
void plutovg_matrix_init_translate(plutovg_matrix_t* matrix, float tx, float ty)
{
plutovg_matrix_init(matrix, 1, 0, 0, 1, tx, ty);
}
void plutovg_matrix_init_scale(plutovg_matrix_t* matrix, float sx, float sy)
{
plutovg_matrix_init(matrix, sx, 0, 0, sy, 0, 0);
}
void plutovg_matrix_init_rotate(plutovg_matrix_t* matrix, float angle)
{
float c = cosf(angle);
float s = sinf(angle);
plutovg_matrix_init(matrix, c, s, -s, c, 0, 0);
}
void plutovg_matrix_init_shear(plutovg_matrix_t* matrix, float shx, float shy)
{
plutovg_matrix_init(matrix, 1, tanf(shy), tanf(shx), 1, 0, 0);
}
void plutovg_matrix_translate(plutovg_matrix_t* matrix, float tx, float ty)
{
plutovg_matrix_t m;
plutovg_matrix_init_translate(&m, tx, ty);
plutovg_matrix_multiply(matrix, &m, matrix);
}
void plutovg_matrix_scale(plutovg_matrix_t* matrix, float sx, float sy)
{
plutovg_matrix_t m;
plutovg_matrix_init_scale(&m, sx, sy);
plutovg_matrix_multiply(matrix, &m, matrix);
}
void plutovg_matrix_rotate(plutovg_matrix_t* matrix, float angle)
{
plutovg_matrix_t m;
plutovg_matrix_init_rotate(&m, angle);
plutovg_matrix_multiply(matrix, &m, matrix);
}
void plutovg_matrix_shear(plutovg_matrix_t* matrix, float shx, float shy)
{
plutovg_matrix_t m;
plutovg_matrix_init_shear(&m, shx, shy);
plutovg_matrix_multiply(matrix, &m, matrix);
}
void plutovg_matrix_multiply(plutovg_matrix_t* matrix, const plutovg_matrix_t* left, const plutovg_matrix_t* right)
{
float a = left->a * right->a + left->b * right->c;
float b = left->a * right->b + left->b * right->d;
float c = left->c * right->a + left->d * right->c;
float d = left->c * right->b + left->d * right->d;
float e = left->e * right->a + left->f * right->c + right->e;
float f = left->e * right->b + left->f * right->d + right->f;
plutovg_matrix_init(matrix, a, b, c, d, e, f);
}
bool plutovg_matrix_invert(const plutovg_matrix_t* matrix, plutovg_matrix_t* inverse)
{
float det = (matrix->a * matrix->d - matrix->b * matrix->c);
if(det == 0.f)
return false;
if(inverse) {
float inv_det = 1.f / det;
float a = matrix->a * inv_det;
float b = matrix->b * inv_det;
float c = matrix->c * inv_det;
float d = matrix->d * inv_det;
float e = (matrix->c * matrix->f - matrix->d * matrix->e) * inv_det;
float f = (matrix->b * matrix->e - matrix->a * matrix->f) * inv_det;
plutovg_matrix_init(inverse, d, -b, -c, a, e, f);
}
return true;
}
void plutovg_matrix_map(const plutovg_matrix_t* matrix, float x, float y, float* xx, float* yy)
{
*xx = x * matrix->a + y * matrix->c + matrix->e;
*yy = x * matrix->b + y * matrix->d + matrix->f;
}
void plutovg_matrix_map_point(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst)
{
plutovg_matrix_map(matrix, src->x, src->y, &dst->x, &dst->y);
}
void plutovg_matrix_map_points(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst, int count)
{
for(int i = 0; i < count; ++i) {
plutovg_matrix_map_point(matrix, &src[i], &dst[i]);
}
}
void plutovg_matrix_map_rect(const plutovg_matrix_t* matrix, const plutovg_rect_t* src, plutovg_rect_t* dst)
{
plutovg_point_t p[4];
p[0].x = src->x;
p[0].y = src->y;
p[1].x = src->x + src->w;
p[1].y = src->y;
p[2].x = src->x + src->w;
p[2].y = src->y + src->h;
p[3].x = src->x;
p[3].y = src->y + src->h;
plutovg_matrix_map_points(matrix, p, p, 4);
float l = p[0].x;
float t = p[0].y;
float r = p[0].x;
float b = p[0].y;
for(int i = 1; i < 4; i++) {
if(p[i].x < l) l = p[i].x;
if(p[i].x > r) r = p[i].x;
if(p[i].y < t) t = p[i].y;
if(p[i].y > b) b = p[i].y;
}
dst->x = l;
dst->y = t;
dst->w = r - l;
dst->h = b - t;
}
static int parse_matrix_parameters(const char** begin, const char* end, float values[6], int required, int optional)
{
if(!plutovg_skip_ws_and_delim(begin, end, '('))
return 0;
int count = 0;
int max_count = required + optional;
bool has_trailing_comma = false;
for(; count < max_count; ++count) {
if(!plutovg_parse_number(begin, end, values + count))
break;
plutovg_skip_ws_or_comma(begin, end, &has_trailing_comma);
}
if(!has_trailing_comma && (count == required || count == max_count)
&& plutovg_skip_delim(begin, end, ')')) {
return count;
}
return 0;
}
bool plutovg_matrix_parse(plutovg_matrix_t* matrix, const char* data, int length)
{
float values[6];
plutovg_matrix_init_identity(matrix);
if(length == -1)
length = strlen(data);
const char* it = data;
const char* end = it + length;
bool has_trailing_comma = false;
plutovg_skip_ws(&it, end);
while(it < end) {
if(plutovg_skip_string(&it, end, "matrix")) {
int count = parse_matrix_parameters(&it, end, values, 6, 0);
if(count == 0)
return false;
plutovg_matrix_t m = { values[0], values[1], values[2], values[3], values[4], values[5] };
plutovg_matrix_multiply(matrix, &m, matrix);
} else if(plutovg_skip_string(&it, end, "translate")) {
int count = parse_matrix_parameters(&it, end, values, 1, 1);
if(count == 0)
return false;
if(count == 1) {
plutovg_matrix_translate(matrix, values[0], 0);
} else {
plutovg_matrix_translate(matrix, values[0], values[1]);
}
} else if(plutovg_skip_string(&it, end, "scale")) {
int count = parse_matrix_parameters(&it, end, values, 1, 1);
if(count == 0)
return false;
if(count == 1) {
plutovg_matrix_scale(matrix, values[0], values[0]);
} else {
plutovg_matrix_scale(matrix, values[0], values[1]);
}
} else if(plutovg_skip_string(&it, end, "rotate")) {
int count = parse_matrix_parameters(&it, end, values, 1, 2);
if(count == 0)
return false;
if(count == 3)
plutovg_matrix_translate(matrix, values[1], values[2]);
plutovg_matrix_rotate(matrix, PLUTOVG_DEG2RAD(values[0]));
if(count == 3) {
plutovg_matrix_translate(matrix, -values[1], -values[2]);
}
} else if(plutovg_skip_string(&it, end, "skewX")) {
int count = parse_matrix_parameters(&it, end, values, 1, 0);
if(count == 0)
return false;
plutovg_matrix_shear(matrix, PLUTOVG_DEG2RAD(values[0]), 0);
} else if(plutovg_skip_string(&it, end, "skewY")) {
int count = parse_matrix_parameters(&it, end, values, 1, 0);
if(count == 0)
return false;
plutovg_matrix_shear(matrix, 0, PLUTOVG_DEG2RAD(values[0]));
} else {
return false;
}
plutovg_skip_ws_or_comma(&it, end, &has_trailing_comma);
}
return !has_trailing_comma;
}