diff options
Diffstat (limited to 'src/transform')
-rw-r--r-- | src/transform/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/transform/transform.c | 170 | ||||
-rw-r--r-- | src/transform/transform.h | 26 | ||||
-rw-r--r-- | src/transform/transform.test.c | 316 |
4 files changed, 519 insertions, 0 deletions
diff --git a/src/transform/CMakeLists.txt b/src/transform/CMakeLists.txt new file mode 100644 index 0000000..cf9e78a --- /dev/null +++ b/src/transform/CMakeLists.txt @@ -0,0 +1,7 @@ +project(kalmia) + +target_sources(kalmia PUBLIC transform.c) + +if (KALMIA_BUILD_TESTS) + target_sources(kalmia-tests PUBLIC transform.test.c) +endif() diff --git a/src/transform/transform.c b/src/transform/transform.c new file mode 100644 index 0000000..b0f6dc9 --- /dev/null +++ b/src/transform/transform.c @@ -0,0 +1,170 @@ +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include <kalmia.h> +#include <ezxml.h> +#include "transform.h" + + +#define TWO_PI 6.2831853071796f + + +int kai_identity(ka_matrix_t *m) +{ + memset(*m, 0, sizeof(ka_matrix_t)); + (*m)[0] = 1.0f; + (*m)[5] = 1.0f; + (*m)[10] = 1.0f; + (*m)[15] = 1.0f; + + return 0; +} + + +int kai_multiply(ka_matrix_t *dest, ka_matrix_t A, ka_matrix_t B) +{ + ka_matrix_t C; + memset(C, 0, sizeof(ka_matrix_t)); + + int i, j, k; + int a_ind, b_ind, c_ind; + for (i=0; i<4; i++) { + for (j=0; j<4; j++) { + c_ind = (4*i) + j; + for (k=0; k<4; k++) { + a_ind = (4*i) + k; + b_ind = (4*k) + j; + C[c_ind] += A[a_ind] * B[b_ind]; + } + } + } + + memcpy(*dest, C, sizeof(ka_matrix_t)); + return 0; +} + + +int kai_parse_matrix(ka_matrix_t *m, ezxml_t tag) +{ + if (strcmp("matrix", ezxml_name(tag)) != 0) + return -1; + + char *str = ezxml_txt(tag); + char *end; + int i; + for (i=0; i<16; i++) { + (*m)[i] = strtod(str, &end); + str = end; + } + + return 0; +} + + +int kai_parse_rotate(ka_matrix_t *m, ezxml_t tag) +{ + if (strcmp("rotate", ezxml_name(tag)) != 0) + return -1; + + char *str = ezxml_txt(tag); + char *end; + int i; + double rot[4]; + for (i=0; i<4; i++) { + rot[i] = strtod(str, &end); + str = end; + } + + double x, y, z, angle; + x = rot[0]; + y = rot[1]; + z = rot[2]; + angle = rot[3]; + + /* normalize length */ + double axis_len = (x*x) + (y*y) + (z*z); + axis_len = sqrt(axis_len); + x /= axis_len; + y /= axis_len; + z /= axis_len; + + /* convert angle to radians */ + angle *= TWO_PI / 360; + + /* compute rotation matrix entries */ + double co = cos(angle); + double unco = 1 - co; + double si = sin(angle); + + (*m)[0] = (x*x*unco) + co; + (*m)[1] = (x*y*unco) - (z*si); + (*m)[2] = (x*z*unco) + (y*si); + (*m)[3] = 0.0f; + (*m)[4] = (y*x*unco) + (z*si); + (*m)[5] = (y*y*unco) + co; + (*m)[6] = (y*z*unco) - (x*si); + (*m)[7] = 0.0f; + (*m)[8] = (z*x*unco) - (y*si); + (*m)[9] = (z*y*unco) + (x*si); + (*m)[10] = (z*z*unco) + co; + (*m)[11] = 0.0f; + (*m)[12] = 0.0f; + (*m)[13] = 0.0f; + (*m)[14] = 0.0f; + (*m)[15] = 1.0f; + + return 0; +} + + +int kai_parse_scale(ka_matrix_t *m, ezxml_t tag) +{ + if (strcmp("scale", ezxml_name(tag)) != 0) + return -1; + + char *str = ezxml_txt(tag); + char *end; + int i; + double scale[3]; + for (i=0; i<3; i++) { + scale[i] = strtod(str, &end); + str = end; + } + + memset(*m, 0, 16*sizeof(double)); + (*m)[0] = scale[0]; + (*m)[5] = scale[1]; + (*m)[10] = scale[2]; + (*m)[15] = 1.0f; + + return 0; +} + + +int kai_parse_translate(ka_matrix_t *m, ezxml_t tag) +{ + if (strcmp("translate", ezxml_name(tag)) != 0) + return -1; + + char *str = ezxml_txt(tag); + char *end; + int i; + double move[3]; + for (i=0; i<3; i++) { + move[i] = strtod(str, &end); + str = end; + } + + memset(*m, 0, sizeof(ka_matrix_t)); + + (*m)[0] = 1.0f; + (*m)[3] = move[0]; + (*m)[5] = 1.0f; + (*m)[7] = move[1]; + (*m)[10] = 1.0f; + (*m)[11] = move[2]; + (*m)[15] = 1.0f; + + return 0; +} diff --git a/src/transform/transform.h b/src/transform/transform.h new file mode 100644 index 0000000..db582ac --- /dev/null +++ b/src/transform/transform.h @@ -0,0 +1,26 @@ +#ifndef KALMIA_TRANSLATE_H +#define KALMIA_TRANSLATE_H + +#include <kalmia.h> +#include <ezxml.h> + + +/* fill a ka_matrix_t with the identity matrix */ +int kai_identity(ka_matrix_t *m); + +/* multiply two matrices together */ +int kai_multiply(ka_matrix_t *dest, ka_matrix_t A, ka_matrix_t B); + +/* parse a <matrix> tag into a ka_matrix_t */ +int kai_parse_matrix(ka_matrix_t *m, ezxml_t tag); + +/* parse a <rotate> tag into a ka_matrix_t */ +int kai_parse_rotate(ka_matrix_t *m, ezxml_t tag); + +/* parse a <scale> tag into a ka_matrix_t */ +int kai_parse_scale(ka_matrix_t *m, ezxml_t tag); + +/* parse a <translate> tag into a ka_matrix_t */ +int kai_parse_translate(ka_matrix_t *m, ezxml_t tag); + +#endif diff --git a/src/transform/transform.test.c b/src/transform/transform.test.c new file mode 100644 index 0000000..4b1e329 --- /dev/null +++ b/src/transform/transform.test.c @@ -0,0 +1,316 @@ +#include <string.h> +#include <kalmia.h> +#include "test/test.h" +#include "transform.h" + +void create_identity(); +void multiply(); + +void parse_matrix_fail_nonmatrix(); +void parse_identity(); + +void parse_rotate_fail(); +void parse_rotate(); + +void parse_scale_fail(); +void parse_scale(); + +void parse_translate_fail(); +void parse_translate(); + + +void suite_transform() +{ + lily_run_test(create_identity); + lily_run_test(multiply); + lily_run_test(parse_matrix_fail_nonmatrix); + lily_run_test(parse_identity); + lily_run_test(parse_rotate_fail); + lily_run_test(parse_rotate); + lily_run_test(parse_scale_fail); + lily_run_test(parse_scale); + lily_run_test(parse_translate_fail); + lily_run_test(parse_translate); +} + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* ======== basic ======== */ + +void create_identity() +{ + ka_matrix_t mat; + mat[0] = 100; + int rc = kai_identity(&mat); + lily_assert_true(rc == 0); + + lily_assert_float_equal(mat[0], 1.0f, 1e-3); + lily_assert_float_equal(mat[1], 0.0f, 1e-3); + lily_assert_float_equal(mat[2], 0.0f, 1e-3); + lily_assert_float_equal(mat[3], 0.0f, 1e-3); + lily_assert_float_equal(mat[4], 0.0f, 1e-3); + lily_assert_float_equal(mat[5], 1.0f, 1e-3); + lily_assert_float_equal(mat[6], 0.0f, 1e-3); + lily_assert_float_equal(mat[7], 0.0f, 1e-3); + lily_assert_float_equal(mat[8], 0.0f, 1e-3); + lily_assert_float_equal(mat[9], 0.0f, 1e-3); + lily_assert_float_equal(mat[10], 1.0f, 1e-3); + lily_assert_float_equal(mat[11], 0.0f, 1e-3); + lily_assert_float_equal(mat[12], 0.0f, 1e-3); + lily_assert_float_equal(mat[13], 0.0f, 1e-3); + lily_assert_float_equal(mat[14], 0.0f, 1e-3); + lily_assert_float_equal(mat[15], 1.0f, 1e-3); +} + + +void multiply() +{ + ka_matrix_t A = { + 2.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 3.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + ka_matrix_t B = { + 0.0f, 3.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 2.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + int rc = kai_multiply(&A, A, B); + lily_assert_true(rc == 0); + + lily_assert_float_equal(A[0], 0.0f, 1e-3); + lily_assert_float_equal(A[1], 8.0f, 1e-3); + lily_assert_float_equal(A[2], 2.0f, 1e-3); + lily_assert_float_equal(A[3], 0.0f, 1e-3); + + lily_assert_float_equal(A[4], 3.0f, 1e-3); + lily_assert_float_equal(A[5], 0.0f, 1e-3); + lily_assert_float_equal(A[6], 3.0f, 1e-3); + lily_assert_float_equal(A[7], 0.0f, 1e-3); + + lily_assert_float_equal(A[8], 0.0f, 1e-3); + lily_assert_float_equal(A[9], 2.0f, 1e-3); + lily_assert_float_equal(A[10], 2.0f, 1e-3); + lily_assert_float_equal(A[11], 0.0f, 1e-3); + + lily_assert_float_equal(A[12], 0.0f, 1e-3); + lily_assert_float_equal(A[13], 0.0f, 1e-3); + lily_assert_float_equal(A[14], 0.0f, 1e-3); + lily_assert_float_equal(A[15], 1.0f, 1e-3); +} + + +/* ======== matrix ======== */ +void parse_matrix_fail_nonmatrix() +{ + char str[128]; + strncpy(str, "<nonmatrix></nonmatrix>", 128); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + int rc = kai_parse_matrix(&mat, tag); + lily_assert_true(rc != 0); + + ezxml_free(tag); +} + + +void parse_identity() +{ + char str[512]; + strncpy( + str, + "<matrix>\n" + " 1 0 0 0\n" + " 0 1 0 0\n" + " 0 0 1 0\n" + " 0 0 0 1\n" + "</matrix>", + 512 + ); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + mat[0] = 100; + int rc = kai_parse_matrix(&mat, tag); + lily_assert_true(rc == 0); + ezxml_free(tag); + + lily_assert_float_equal(mat[0], 1.0f, 1e-3); + lily_assert_float_equal(mat[1], 0.0f, 1e-3); + lily_assert_float_equal(mat[2], 0.0f, 1e-3); + lily_assert_float_equal(mat[3], 0.0f, 1e-3); + lily_assert_float_equal(mat[4], 0.0f, 1e-3); + lily_assert_float_equal(mat[5], 1.0f, 1e-3); + lily_assert_float_equal(mat[6], 0.0f, 1e-3); + lily_assert_float_equal(mat[7], 0.0f, 1e-3); + lily_assert_float_equal(mat[8], 0.0f, 1e-3); + lily_assert_float_equal(mat[9], 0.0f, 1e-3); + lily_assert_float_equal(mat[10], 1.0f, 1e-3); + lily_assert_float_equal(mat[11], 0.0f, 1e-3); + lily_assert_float_equal(mat[12], 0.0f, 1e-3); + lily_assert_float_equal(mat[13], 0.0f, 1e-3); + lily_assert_float_equal(mat[14], 0.0f, 1e-3); + lily_assert_float_equal(mat[15], 1.0f, 1e-3); +} + + +/* ======== rotate ======== */ +void parse_rotate_fail() +{ + char str[128]; + strncpy(str, "<non></non>", 128); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + int rc = kai_parse_rotate(&mat, tag); + lily_assert_true(rc != 0); + + ezxml_free(tag); +} + + +void parse_rotate() +{ + char str[512]; + strncpy( + str, + "<rotate>\n" + " 0 1 0 90.0\n" + "</rotate>", + 512 + ); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + mat[0] = 100; + int rc = kai_parse_rotate(&mat, tag); + lily_assert_true(rc == 0); + ezxml_free(tag); + + lily_assert_float_equal(mat[0], 0.0f, 1e-3); + lily_assert_float_equal(mat[1], 0.0f, 1e-3); + lily_assert_float_equal(mat[2], 1.0f, 1e-3); + lily_assert_float_equal(mat[3], 0.0f, 1e-3); + lily_assert_float_equal(mat[4], 0.0f, 1e-3); + lily_assert_float_equal(mat[5], 1.0f, 1e-3); + lily_assert_float_equal(mat[6], 0.0f, 1e-3); + lily_assert_float_equal(mat[7], 0.0f, 1e-3); + lily_assert_float_equal(mat[8], -1.0f, 1e-3); + lily_assert_float_equal(mat[9], 0.0f, 1e-3); + lily_assert_float_equal(mat[10], 0.0f, 1e-3); + lily_assert_float_equal(mat[11], 0.0f, 1e-3); + lily_assert_float_equal(mat[12], 0.0f, 1e-3); + lily_assert_float_equal(mat[13], 0.0f, 1e-3); + lily_assert_float_equal(mat[14], 0.0f, 1e-3); + lily_assert_float_equal(mat[15], 1.0f, 1e-3); +} + + +/* ======== scale ======== */ +void parse_scale_fail() +{ + char str[128]; + strncpy(str, "<non></non>", 128); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + int rc = kai_parse_scale(&mat, tag); + lily_assert_true(rc != 0); + + ezxml_free(tag); +} + + +void parse_scale() +{ + char str[512]; + strncpy( + str, + "<scale>\n" + " 10 5 -1\n" + "</scale>", + 512 + ); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + mat[0] = 100; + int rc = kai_parse_scale(&mat, tag); + lily_assert_true(rc == 0); + ezxml_free(tag); + + lily_assert_float_equal(mat[0], 10.0f, 1e-3); + lily_assert_float_equal(mat[1], 0.0f, 1e-3); + lily_assert_float_equal(mat[2], 0.0f, 1e-3); + lily_assert_float_equal(mat[3], 0.0f, 1e-3); + lily_assert_float_equal(mat[4], 0.0f, 1e-3); + lily_assert_float_equal(mat[5], 5.0f, 1e-3); + lily_assert_float_equal(mat[6], 0.0f, 1e-3); + lily_assert_float_equal(mat[7], 0.0f, 1e-3); + lily_assert_float_equal(mat[8], 0.0f, 1e-3); + lily_assert_float_equal(mat[9], 0.0f, 1e-3); + lily_assert_float_equal(mat[10],-1.0f, 1e-3); + lily_assert_float_equal(mat[11], 0.0f, 1e-3); + lily_assert_float_equal(mat[12], 0.0f, 1e-3); + lily_assert_float_equal(mat[13], 0.0f, 1e-3); + lily_assert_float_equal(mat[14], 0.0f, 1e-3); + lily_assert_float_equal(mat[15], 1.0f, 1e-3); +} + + +/* ======== translate ======== */ +void parse_translate_fail() +{ + char str[128]; + strncpy(str, "<non></non>", 128); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + int rc = kai_parse_translate(&mat, tag); + lily_assert_true(rc != 0); + + ezxml_free(tag); +} + + +void parse_translate() +{ + char str[512]; + strncpy( + str, + "<translate>\n" + " 10 5 -1\n" + "</translate>", + 512 + ); + ezxml_t tag = ezxml_parse_str(str, strlen(str)); + + ka_matrix_t mat; + mat[0] = 100; + int rc = kai_parse_translate(&mat, tag); + lily_assert_true(rc == 0); + ezxml_free(tag); + + lily_assert_float_equal(mat[0], 1.0f, 1e-3); + lily_assert_float_equal(mat[1], 0.0f, 1e-3); + lily_assert_float_equal(mat[2], 0.0f, 1e-3); + lily_assert_float_equal(mat[3], 10.0f, 1e-3); + lily_assert_float_equal(mat[4], 0.0f, 1e-3); + lily_assert_float_equal(mat[5], 1.0f, 1e-3); + lily_assert_float_equal(mat[6], 0.0f, 1e-3); + lily_assert_float_equal(mat[7], 5.0f, 1e-3); + lily_assert_float_equal(mat[8], 0.0f, 1e-3); + lily_assert_float_equal(mat[9], 0.0f, 1e-3); + lily_assert_float_equal(mat[10], 1.0f, 1e-3); + lily_assert_float_equal(mat[11],-1.0f, 1e-3); + lily_assert_float_equal(mat[12], 0.0f, 1e-3); + lily_assert_float_equal(mat[13], 0.0f, 1e-3); + lily_assert_float_equal(mat[14], 0.0f, 1e-3); + lily_assert_float_equal(mat[15], 1.0f, 1e-3); +} |