242 lines
6.5 KiB
C
Executable File
242 lines
6.5 KiB
C
Executable File
/**
|
|
* @file lv_matrix.c
|
|
*
|
|
*/
|
|
|
|
/*********************
|
|
* INCLUDES
|
|
*********************/
|
|
|
|
#include "lv_matrix.h"
|
|
|
|
#if LV_USE_MATRIX
|
|
|
|
#include "../stdlib/lv_string.h"
|
|
#include "lv_math.h"
|
|
#include <math.h>
|
|
#include <float.h>
|
|
#include "../misc/lv_log.h"
|
|
/*********************
|
|
* DEFINES
|
|
*********************/
|
|
#ifndef M_PI
|
|
#define M_PI 3.1415926f
|
|
#endif
|
|
|
|
/**********************
|
|
* TYPEDEFS
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC PROTOTYPES
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC VARIABLES
|
|
**********************/
|
|
|
|
/**********************
|
|
* MACROS
|
|
**********************/
|
|
|
|
/**********************
|
|
* GLOBAL FUNCTIONS
|
|
**********************/
|
|
|
|
void lv_matrix_identity(lv_matrix_t * matrix)
|
|
{
|
|
matrix->m[0][0] = 1.0f;
|
|
matrix->m[0][1] = 0.0f;
|
|
matrix->m[0][2] = 0.0f;
|
|
matrix->m[1][0] = 0.0f;
|
|
matrix->m[1][1] = 1.0f;
|
|
matrix->m[1][2] = 0.0f;
|
|
matrix->m[2][0] = 0.0f;
|
|
matrix->m[2][1] = 0.0f;
|
|
matrix->m[2][2] = 1.0f;
|
|
}
|
|
|
|
void lv_matrix_translate(lv_matrix_t * matrix, float dx, float dy)
|
|
{
|
|
if(lv_matrix_is_identity_or_translation(matrix)) {
|
|
/*optimization for matrix translation.*/
|
|
matrix->m[0][2] += dx;
|
|
matrix->m[1][2] += dy;
|
|
return;
|
|
}
|
|
|
|
lv_matrix_t tlm = {{
|
|
{1.0f, 0.0f, dx},
|
|
{0.0f, 1.0f, dy},
|
|
{0.0f, 0.0f, 1.0f},
|
|
}
|
|
};
|
|
|
|
lv_matrix_multiply(matrix, &tlm);
|
|
}
|
|
|
|
void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y)
|
|
{
|
|
lv_matrix_t scm = {{
|
|
{scale_x, 0.0f, 0.0f},
|
|
{0.0f, scale_y, 0.0f},
|
|
{0.0f, 0.0f, 1.0f},
|
|
}
|
|
};
|
|
|
|
lv_matrix_multiply(matrix, &scm);
|
|
}
|
|
|
|
void lv_matrix_rotate(lv_matrix_t * matrix, float degree)
|
|
{
|
|
float radian = degree / 180.0f * (float)M_PI;
|
|
float cos_r = cosf(radian);
|
|
float sin_r = sinf(radian);
|
|
|
|
lv_matrix_t rtm = {{
|
|
{cos_r, -sin_r, 0.0f},
|
|
{sin_r, cos_r, 0.0f},
|
|
{0.0f, 0.0f, 1.0f},
|
|
}
|
|
};
|
|
|
|
lv_matrix_multiply(matrix, &rtm);
|
|
}
|
|
|
|
void lv_matrix_skew(lv_matrix_t * matrix, float skew_x, float skew_y)
|
|
{
|
|
float rskew_x = skew_x / 180.0f * (float)M_PI;
|
|
float rskew_y = skew_y / 180.0f * (float)M_PI;
|
|
float tan_x = tanf(rskew_x);
|
|
float tan_y = tanf(rskew_y);
|
|
|
|
lv_matrix_t skm = {{
|
|
{1.0f, tan_x, 0.0f},
|
|
{tan_y, 1.0f, 0.0f},
|
|
{0.0f, 0.0f, 1.0f},
|
|
}
|
|
};
|
|
|
|
lv_matrix_multiply(matrix, &skm);
|
|
}
|
|
|
|
void lv_matrix_multiply(lv_matrix_t * matrix, const lv_matrix_t * mul)
|
|
{
|
|
/*TODO: use NEON to optimize this function on ARM architecture.*/
|
|
lv_matrix_t tmp;
|
|
|
|
for(int y = 0; y < 3; y++) {
|
|
for(int x = 0; x < 3; x++) {
|
|
tmp.m[y][x] = (matrix->m[y][0] * mul->m[0][x])
|
|
+ (matrix->m[y][1] * mul->m[1][x])
|
|
+ (matrix->m[y][2] * mul->m[2][x]);
|
|
}
|
|
}
|
|
|
|
lv_memcpy(matrix, &tmp, sizeof(lv_matrix_t));
|
|
}
|
|
|
|
bool lv_matrix_inverse(lv_matrix_t * matrix, const lv_matrix_t * m)
|
|
{
|
|
float det00, det01, det02;
|
|
float d;
|
|
bool is_affine;
|
|
|
|
/* Test for identity matrix. */
|
|
if(m == NULL) {
|
|
lv_matrix_identity(matrix);
|
|
return true;
|
|
}
|
|
|
|
det00 = (m->m[1][1] * m->m[2][2]) - (m->m[2][1] * m->m[1][2]);
|
|
det01 = (m->m[2][0] * m->m[1][2]) - (m->m[1][0] * m->m[2][2]);
|
|
det02 = (m->m[1][0] * m->m[2][1]) - (m->m[2][0] * m->m[1][1]);
|
|
|
|
/* Compute determinant. */
|
|
d = (m->m[0][0] * det00) + (m->m[0][1] * det01) + (m->m[0][2] * det02);
|
|
|
|
/* Return 0 if there is no inverse matrix. */
|
|
if(d == 0.0f)
|
|
return false;
|
|
|
|
/* Compute reciprocal. */
|
|
d = 1.0f / d;
|
|
|
|
/* Determine if the matrix is affine. */
|
|
is_affine = (m->m[2][0] == 0.0f) && (m->m[2][1] == 0.0f) && (m->m[2][2] == 1.0f);
|
|
|
|
matrix->m[0][0] = d * det00;
|
|
matrix->m[0][1] = d * ((m->m[2][1] * m->m[0][2]) - (m->m[0][1] * m->m[2][2]));
|
|
matrix->m[0][2] = d * ((m->m[0][1] * m->m[1][2]) - (m->m[1][1] * m->m[0][2]));
|
|
matrix->m[1][0] = d * det01;
|
|
matrix->m[1][1] = d * ((m->m[0][0] * m->m[2][2]) - (m->m[2][0] * m->m[0][2]));
|
|
matrix->m[1][2] = d * ((m->m[1][0] * m->m[0][2]) - (m->m[0][0] * m->m[1][2]));
|
|
matrix->m[2][0] = is_affine ? 0.0f : d * det02;
|
|
matrix->m[2][1] = is_affine ? 0.0f : d * ((m->m[2][0] * m->m[0][1]) - (m->m[0][0] * m->m[2][1]));
|
|
matrix->m[2][2] = is_affine ? 1.0f : d * ((m->m[0][0] * m->m[1][1]) - (m->m[1][0] * m->m[0][1]));
|
|
|
|
/* Success. */
|
|
return true;
|
|
}
|
|
|
|
lv_point_precise_t lv_matrix_transform_precise_point(const lv_matrix_t * matrix, const lv_point_precise_t * point)
|
|
{
|
|
lv_point_precise_t p;
|
|
lv_value_precise_t w = point->x * matrix->m[2][0] + point->y * matrix->m[2][1] + matrix->m[2][2];
|
|
if(LV_ABS(w) < FLT_EPSILON) {
|
|
LV_LOG_ERROR("matrix is invalid");
|
|
p.x = 0;
|
|
p.y = 0;
|
|
}
|
|
else {
|
|
lv_value_precise_t inv_w = 1.0f / w;
|
|
p.x = (lv_value_precise_t)roundf((point->x * matrix->m[0][0] + point->y * matrix->m[0][1] + matrix->m[0][2]) * inv_w);
|
|
p.y = (lv_value_precise_t)roundf((point->x * matrix->m[1][0] + point->y * matrix->m[1][1] + matrix->m[1][2]) * inv_w);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
lv_area_t lv_matrix_transform_area(const lv_matrix_t * matrix, const lv_area_t * area)
|
|
{
|
|
lv_area_t res;
|
|
lv_point_precise_t p[4] = {
|
|
{area->x1, area->y1},
|
|
{area->x1, area->y2},
|
|
{area->x2, area->y1},
|
|
{area->x2, area->y2},
|
|
};
|
|
p[0] = lv_matrix_transform_precise_point(matrix, &p[0]);
|
|
p[1] = lv_matrix_transform_precise_point(matrix, &p[1]);
|
|
p[2] = lv_matrix_transform_precise_point(matrix, &p[2]);
|
|
p[3] = lv_matrix_transform_precise_point(matrix, &p[3]);
|
|
|
|
res.x1 = (int32_t)(LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x));
|
|
res.x2 = (int32_t)(LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x));
|
|
res.y1 = (int32_t)(LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y));
|
|
res.y2 = (int32_t)(LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y));
|
|
|
|
return res;
|
|
}
|
|
|
|
bool lv_matrix_is_identity(const lv_matrix_t * matrix)
|
|
{
|
|
return (matrix->m[0][2] == 0.0f && matrix->m[1][2] == 0.0f && lv_matrix_is_identity_or_translation(matrix));
|
|
}
|
|
|
|
bool lv_matrix_is_identity_or_translation(const lv_matrix_t * matrix)
|
|
{
|
|
return (matrix->m[0][0] == 1.0f &&
|
|
matrix->m[0][1] == 0.0f &&
|
|
matrix->m[1][0] == 0.0f &&
|
|
matrix->m[1][1] == 1.0f &&
|
|
matrix->m[2][0] == 0.0f &&
|
|
matrix->m[2][1] == 0.0f &&
|
|
matrix->m[2][2] == 1.0f);
|
|
}
|
|
|
|
/**********************
|
|
* STATIC FUNCTIONS
|
|
**********************/
|
|
|
|
#endif /*LV_USE_MATRIX*/
|