From: LeonardoBizzoni Date: Thu, 6 Nov 2025 13:41:47 +0000 (+0100) Subject: linear algebra generator changes X-Git-Url: http://git.leonardobizzoni.com/?a=commitdiff_plain;h=56f137041483de6c17f4c54dba583867e797a3fb;p=CBuild linear algebra generator changes --- diff --git a/cbuild.h b/cbuild.h index 14e2a1d..c93ad1f 100644 --- a/cbuild.h +++ b/cbuild.h @@ -219,7 +219,7 @@ enum { (sizeof((char*[]){__VA_ARGS__}) / sizeof(char*))) #define cb_println(Level, Fmt, ...) cb_print((Level), Fmt "\n", ##__VA_ARGS__) #define cb_rebuild_self(argc, argv) _cb_rebuild(argc, argv, __FILE__, 0) -#define cb_rebuild_self_with(argc, argv, ...) _cb_rebuild(argc, argv, __FILE__, __VA_ARGS__, 0) +#define cb_rebuild_self_with(argc, argv, ...) _cb_rebuild(argc, argv, __FILE__, __VA_ARGS__, (char*)0) #define cb_is_outdated(OutputFile, ...) _cb_is_outdated((OutputFile), __VA_ARGS__, 0) #define cb_cmd_run(Cmd, ...) _cb_cmd_run((Cmd), (struct Cb_Cmd_RunArgs) { \ .async = false, \ @@ -527,7 +527,6 @@ static bool cb_file_exists(char *path) { return access(path, F_OK) == 0; } - internal bool _cb_is_outdated(char *output, ...) { struct CB_PathList sources = {}; va_list args; diff --git a/extra/cbuild_codegen.h b/extra/cbuild_codegen.h index 88855f2..1eca80e 100644 --- a/extra/cbuild_codegen.h +++ b/extra/cbuild_codegen.h @@ -31,7 +31,7 @@ static void cb_gen_write(CB_Generator *gen, char *filepath, bool append_mode) { for (size_t i = 0; i < gen->count; ++i) { strcat(full_string, gen->values[i]); } - cb_handle_write(file, full_string); + _cb_handle_write_dyn(file, full_string); free(full_string); cb_handle_close(file); cb_dyn_free(gen); diff --git a/extra/cbuild_linagen.h b/extra/cbuild_linagen.h index 5f6a796..707162b 100644 --- a/extra/cbuild_linagen.h +++ b/extra/cbuild_linagen.h @@ -1,6 +1,13 @@ #ifndef CBUILD_EXTRA_LINAGEN_H #define CBUILD_EXTRA_LINAGEN_H +#define CB_LINAGEN_VECN_COPY_CAP 4 +#define CB_LINAGEN_MATNN_COPY_CAP 4 + +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) + +#define _USE_MATH_DEFINES +#include #include internal void @@ -22,6 +29,9 @@ cb_linagen_typedef_vecn_unnamed(CB_Generator *gen, char *type, int32_t n); static void cb_linagen_typedef_matnn(CB_Generator *gen, char *type, int32_t n); +static inline void +cb_linagen_defun_vecn(CB_Generator *gen, char *type, + int32_t n, bool implementation); static inline void cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, bool implementation); @@ -81,6 +91,19 @@ static void cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, int32_t n, bool implementation); +static void +cb_linagen_defun_mat4_transform_translate(CB_Generator *gen, char *type, + bool implementation); +static void +cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, + bool implementation); +static void +cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, + bool implementation); +static void +cb_linagen_defun_mat4_projection_orthographics(CB_Generator *gen, char *type, + bool implementation); + // ====================================================================== // Implementations @@ -144,6 +167,26 @@ cb_linagen_typedef_matnn(CB_Generator *gen, char *type, int32_t n) { n, suffix)); } +static inline void +cb_linagen_defun_vecn(CB_Generator *gen, char *type, + int32_t n, bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s", + n, suffix, n, type)); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push_func_arg(gen, cb_format("%s _%d", type, i)); + } + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res.values[%d] = _%d;", i, i)); + } + cb_gen_push(gen, "\n return res;" "\n}\n\n"); +} + static inline void cb_linagen_defun_vecn_add(CB_Generator *gen, char *type, int32_t n, bool implementation) { @@ -173,12 +216,11 @@ cb_linagen_defun_vecn_hadamard_div(CB_Generator *gen, char *type, static inline void cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn bool vec%d%s_equal", - n, type)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v1", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v2", n, vec_suffix)); + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn bool vec%d%s_equal", n, type)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v2", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } @@ -193,12 +235,12 @@ cb_linagen_defun_vecn_equal(CB_Generator *gen, char *type, static inline void cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); + char *suffix = strdup(type); + *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn bool vec%d%s_near", n, type)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v1", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v2", n, vec_suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v2", n, suffix)); cb_gen_push_func_arg(gen, "float eps"); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } @@ -214,98 +256,133 @@ cb_linagen_defun_vecn_near(CB_Generator *gen, char *type, static inline void cb_linagen_defun_vecn_lerp(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_lerp", n, type)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *restrict res", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict start", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict end", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("%s t", type)); - cb_gen_push_func_end(gen, implementation); - if (!implementation) { return; } - - cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); + char *suffix = strdup(type); + *suffix = char_toupper(*type); + if (n <= CB_LINAGEN_VECN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s_lerp", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict start", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict end", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("%s t", type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res.values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); + } + cb_gen_push(gen, "\n return res;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_lerp", n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s *restrict res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict start", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict end", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("%s t", type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res->values[%d] = start->values[%d] * (1 - t) + end->values[%d] * t;", i, i, i)); + } + cb_gen_push(gen, "\n}\n\n"); } - cb_gen_push(gen, "\n}\n\n"); } static inline void cb_linagen_defun_vec3_cross(CB_Generator *gen, char *type, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec3%s_cross", type)); - cb_gen_push_func_arg(gen, cb_format("Vec3%s *restrict res", vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec3%s *restrict v1", vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec3%s *restrict v2", vec_suffix)); + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec3%s vec3%s_cross", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("Vec3%s v1", suffix)); + cb_gen_push_func_arg(gen, cb_format("Vec3%s v2", suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, cb_format(" {", vec_suffix)); - cb_gen_push(gen, "\n res->values[0] = v1->values[1] * v2->values[2] - v1->values[2] * v2->values[1];"); - cb_gen_push(gen, "\n res->values[1] = v1->values[2] * v2->values[0] - v1->values[0] * v2->values[2];"); - cb_gen_push(gen, "\n res->values[2] = v1->values[0] * v2->values[1] - v1->values[1] * v2->values[0];"); - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, cb_format(" {" "\n Vec3%s res = {0};", suffix)); + cb_gen_push(gen, "\n res.values[0] = v1.values[1] * v2.values[2] - v1.values[2] * v2.values[1];"); + cb_gen_push(gen, "\n res.values[1] = v1.values[2] * v2.values[0] - v1.values[0] * v2.values[2];"); + cb_gen_push(gen, "\n res.values[2] = v1.values[0] * v2.values[1] - v1.values[1] * v2.values[0];"); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); } static void cb_linagen_defun_vecn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_scale", n, type)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("%s k", type)); - cb_gen_push_func_end(gen, implementation); - if (!implementation) { return; } - - cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] * k;", i, i)); + char *suffix = strdup(type); + *suffix = char_toupper(*type); + if (n <= CB_LINAGEN_VECN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s_scale", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s v", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("%s k", type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n v.values[%d] *= k;", i, i)); + } + cb_gen_push(gen, "\n return v;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_scale", n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("%s k", type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] * k;", i, i)); + } + cb_gen_push(gen, "\n}\n\n"); } - cb_gen_push(gen, "\n}\n\n"); } static void cb_linagen_defun_vecn_normalize(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_normalize", n, type)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, vec_suffix)); - cb_gen_push_func_end(gen, implementation); - if (!implementation) { return; } - - cb_gen_push(gen, cb_format(" {\n %s dot = {0};", type)); - for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n dot += v1->values[%d] * v1->values[%d];", i, i, i)); - } - - cb_gen_push(gen, cb_format("\n float magnitude = sqrtf((float)dot);" , - n, type)); - - cb_gen_push(gen, "\n if (magnitude == 0.f) { return; }"); - for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] / magnitude;", - i, i, type)); + char *suffix = strdup(type); + *suffix = char_toupper(*type); + if (n <= CB_LINAGEN_VECN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s_normalize", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s v", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, cb_format(" {\n %s dot = {0};", type)); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n dot += v.values[%d] * v.values[%d];", i, i)); + } + cb_gen_push(gen, "\n float magnitude = sqrtf((float)dot);" + "\n if (magnitude == 0.f) { return v; }"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n v.values[%d] /= magnitude;", i, type)); + } + cb_gen_push(gen, "\n return v;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_normalize", n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, cb_format(" {\n %s dot = {0};", type)); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n dot += v1->values[%d] * v1->values[%d];", i, i, i)); + } + cb_gen_push(gen, "\n float magnitude = sqrtf((float)dot);" + "\n if (magnitude == 0.f) { return; }"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] / magnitude;", + i, i, type)); + } + cb_gen_push(gen, "\n}\n\n"); } - - cb_gen_push(gen, "\n}\n\n"); } static void cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn %s vec%d%s_dot", - type, n, type)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v2", n, vec_suffix)); + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn %s vec%d%s_dot", type, n, type)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v2", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } @@ -313,18 +390,17 @@ cb_linagen_defun_vecn_dot(CB_Generator *gen, char *type, for (int32_t i = 0; i < n; ++i) { cb_gen_push(gen, cb_format("\n res += v1->values[%d] * v2->values[%d];", i, i, i)); } - cb_gen_push(gen, "\n return res;" - "\n}\n\n"); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); } static void cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); + char *suffix = strdup(type); + *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn float vec%d%s_magnitude", n, type)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, vec_suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } @@ -341,11 +417,11 @@ cb_linagen_defun_vecn_magnitude(CB_Generator *gen, char *type, static void cb_linagen_defun_vecn_magnitude64(CB_Generator *gen, char *type, int32_t n, bool implementation) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); + char *suffix = strdup(type); + *suffix = char_toupper(*type); cb_gen_push_func_begin(gen, cb_format("linagen_fn double vec%d%s_magnitude64", n, type)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, vec_suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } @@ -417,25 +493,45 @@ cb_linagen_defun_vecn_mulm(CB_Generator *gen, char *type, int32_t n, bool implementation) { char *suffix = strdup(type); *suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_mulm", n, type)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *restrict res", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *restrict m", n, suffix)); - cb_gen_push_func_end(gen, implementation); - if (!implementation) { return; } - - cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - char *prefix = ""; - cb_gen_push(gen, cb_format("\n res->values[%d] = ", i)); - for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("%s(v->values[%d] * m->values[%d][%d])", - prefix, j, i, j)); - prefix = " + "; + if (n < MIN(CB_LINAGEN_VECN_COPY_CAP, CB_LINAGEN_MATNN_COPY_CAP)) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s_mulm", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s v", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + for (int32_t i = 0; i < n; ++i) { + char *prefix = ""; + cb_gen_push(gen, cb_format("\n res.values[%d] = ", i)); + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("%s(v.values[%d] * m.values[%d][%d])", + prefix, j, i, j)); + prefix = " + "; + } + cb_gen_push(gen, ";"); } - cb_gen_push(gen, ";"); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_mulm", n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s *restrict res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *restrict m", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + char *prefix = ""; + cb_gen_push(gen, cb_format("\n res->values[%d] = ", i)); + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("%s(v->values[%d] * m->values[%d][%d])", + prefix, j, i, j)); + prefix = " + "; + } + cb_gen_push(gen, ";"); + } + cb_gen_push(gen, "\n}\n\n"); } - cb_gen_push(gen, "\n}\n\n"); } static void @@ -443,21 +539,37 @@ cb_linagen_defun_matnn_scale(CB_Generator *gen, char *type, int32_t n, bool implementation) { char *suffix = strdup(type); *suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_scale", n, type)); - cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m1", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("%s k", type)); - cb_gen_push_func_end(gen, implementation); - if (!implementation) { return; } - - cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = m1->values[%d][%d] * k;", - i, j, i, j)); + if (n < CB_LINAGEN_MATNN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat%d%s mat%d%s_scale", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("%s k", type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("\n m1.values[%d][%d] *= k;", i, j)); + } + } + cb_gen_push(gen, "\n return m1;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_scale", n, type)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("%s k", type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("\n res->values[%d][%d] = m1->values[%d][%d] * k;", + i, j, i, j)); + } } + cb_gen_push(gen, "\n}\n\n"); } - cb_gen_push(gen, "\n}\n\n"); } static inline void @@ -491,95 +603,349 @@ cb_linagen_defun_matnn_dot(CB_Generator *gen, char *type, int32_t n, bool implementation) { char *suffix = strdup(type); *suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_dot", n, type)); - cb_gen_push_func_arg(gen, cb_format("Mat%d%s *restrict res", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m1", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m2", n, suffix)); + if (n <= CB_LINAGEN_MATNN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat%d%s mat%d%s_dot", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m2", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, cb_format(" {" "\n Mat%d%s res = {0};", n, suffix)); + for (int32_t col = 0; col < n; ++col) { + for (int32_t row = 0; row < n; ++row) { + cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", col, row)); + char *prefix = ""; + for (int32_t k = 0; k < n; ++k) { + cb_gen_push(gen, cb_format("%s(m1.values[%d][%d] * m2.values[%d][%d])", + prefix, k, row, col, k)); + prefix = " + "; + } + cb_gen_push(gen, ";"); + } + } + cb_gen_push(gen, "\n return res;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_dot", n, type)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s *restrict res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m2", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t col = 0; col < n; ++col) { + for (int32_t row = 0; row < n; ++row) { + cb_gen_push(gen, cb_format("\n res->values[%d][%d] = ", col, row)); + char *prefix = ""; + for (int32_t k = 0; k < n; ++k) { + cb_gen_push(gen, cb_format("%s(m1->values[%d][%d] * m2->values[%d][%d])", + prefix, k, row, col, k)); + prefix = " + "; + } + cb_gen_push(gen, ";"); + } + } + cb_gen_push(gen, "\n}\n\n"); + } +} + +static void +cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, + int32_t n, bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + if (n <= CB_LINAGEN_MATNN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s mat%d%s_mulv", n, suffix, n, type)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s v", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, cb_format(" {" "\n Vec%d%s res = {0};", n, suffix)); + for (int32_t i = 0; i < n; ++i) { + char *prefix = ""; + cb_gen_push(gen, cb_format("\n res.values[%d] = ", i)); + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("%s(m.values[%d][%d] * v.values[%d])", + prefix, j, i, j)); + prefix = " + "; + } + cb_gen_push(gen, ";"); + } + cb_gen_push(gen, "\n return res;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_mulv", n, type)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s *restrict res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *restrict m", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + char *prefix = ""; + cb_gen_push(gen, cb_format("\n res->values[%d] = ", i)); + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("%s(m->values[%d][%d] * v->values[%d])", + prefix, j, i, j)); + prefix = " + "; + } + cb_gen_push(gen, ";"); + } + cb_gen_push(gen, "\n}\n\n"); + } +} + +static void +cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, + int32_t n, bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + if (n <= CB_LINAGEN_MATNN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat%d%s mat%d%s_identity", n,suffix, n, type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, cb_format(" {" "\n Mat%d%s res = {0};", n, suffix)); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res.values[%d][%d] = 1;", i, i)); + } + cb_gen_push(gen, "\n return res;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_identity", n, type)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + cb_gen_push(gen, "\n memset(res, 0, sizeof *res);"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res->values[%d][%d] = 1;", i, i)); + } + cb_gen_push(gen, "\n}\n\n"); + } +} + +static void +cb_linagen_defun_mat4_transform_translate_by(CB_Generator *gen, char *type, bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_translate_by", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("Mat4%s m", suffix)); + cb_gen_push_func_arg(gen, cb_format("Vec3%s by", suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < 3; ++i) { + cb_gen_push(gen, cb_format("\n m.values[3][%d] += by.values[%d];", i, i)); + } + cb_gen_push(gen, "\n return m;" "\n}\n\n"); +} + +static void +cb_linagen_defun_mat4_transform_translate_to(CB_Generator *gen, char *type, bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_translate_to", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("Mat4%s m", suffix)); + cb_gen_push_func_arg(gen, cb_format("Vec3%s to", suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } cb_gen_push(gen, " {"); - for (int32_t col = 0; col < n; ++col) { - for (int32_t row = 0; row < n; ++row) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = ", col, row)); + for (int32_t i = 0; i < 3; ++i) { + cb_gen_push(gen, cb_format("\n m.values[3][%d] = to.values[%d];", i, i)); + } + cb_gen_push(gen, "\n return m;" "\n}\n\n"); +} + +static void +cb_linagen_defun_mat4_transform_rotate(CB_Generator *gen, char *type, bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_rotate", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("Mat4%s m", suffix)); + cb_gen_push_func_arg(gen, "float degrees"); + cb_gen_push_func_arg(gen, cb_format("Vec3%s axis", suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, cb_format(" {" + "\n Mat4%s res = {0};" + "\n float radians = degrees * %.16ff / 180.f;", suffix, (float)M_PI)); + cb_gen_push(gen, cb_format("\n Mat4%s rot = { .values = {" + "\n { cosf(radians) + axis.values[0]*axis.values[0]*(1 - cosf(radians)), axis.values[0]*axis.values[1]*(1 - cosf(radians)) + axis.values[2]*sinf(radians), axis.values[0]*axis.values[2]*(1 - cosf(radians)) - axis.values[1]*sinf(radians), 0 }," + "\n { axis.values[1]*axis.values[0]*(1 - cosf(radians)) - axis.values[2]*sinf(radians), cosf(radians) + axis.values[1]*axis.values[1]*(1 - cosf(radians)), axis.values[1]*axis.values[2]*(1 - cosf(radians)) + axis.values[0]*sinf(radians), 0 }," + "\n { axis.values[2]*axis.values[0]*(1 - cosf(radians)) + axis.values[1]*sinf(radians), axis.values[2]*axis.values[1]*(1 - cosf(radians)) - axis.values[0]*sinf(radians), cosf(radians) + axis.values[2]*axis.values[2]*(1 - cosf(radians)), 0 }," + "\n { 0, 0, 0, 1 }" + "\n }};" , suffix)); + for (int32_t i = 0; i < 4; ++i) { + for (int32_t j = 0; j < 4; ++j) { + cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", i, j)); char *prefix = ""; - for (int32_t k = 0; k < n; ++k) { - cb_gen_push(gen, cb_format("%s(m1->values[%d][%d] * m2->values[%d][%d])", - prefix, k, row, col, k)); + for (int32_t k = 0; k < 4; ++k) { + cb_gen_push(gen, cb_format("%s(rot.values[%d][%d]) * m.values[%d][%d]", + prefix, k, j, i, k)); prefix = " + "; } cb_gen_push(gen, ";"); } } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); } static void -cb_linagen_defun_matnn_mulv(CB_Generator *gen, char *type, - int32_t n, bool implementation) { +cb_linagen_defun_mat4_transform_rotate_rad(CB_Generator *gen, char *type, bool implementation) { char *suffix = strdup(type); *suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_mulv", n, type)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *restrict res", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *restrict m", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *restrict v", n, suffix)); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_rotate_rad", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("Mat4%s m", suffix)); + cb_gen_push_func_arg(gen, "float radians"); + cb_gen_push_func_arg(gen, cb_format("Vec3%s axis", suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } - cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - char *prefix = ""; - cb_gen_push(gen, cb_format("\n res->values[%d] = ", i)); - for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("%s(m->values[%d][%d] * v->values[%d])", - prefix, j, i, j)); - prefix = " + "; + cb_gen_push(gen, cb_format(" {" "\n Mat4%s res = {0};", suffix)); + cb_gen_push(gen, cb_format("\n Mat4%s rot = { .values = {" + "\n { cosf(radians) + axis.values[0]*axis.values[0]*(1 - cosf(radians)), axis.values[0]*axis.values[1]*(1 - cosf(radians)) + axis.values[2]*sinf(radians), axis.values[0]*axis.values[2]*(1 - cosf(radians)) - axis.values[1]*sinf(radians), 0 }," + "\n { axis.values[1]*axis.values[0]*(1 - cosf(radians)) - axis.values[2]*sinf(radians), cosf(radians) + axis.values[1]*axis.values[1]*(1 - cosf(radians)), axis.values[1]*axis.values[2]*(1 - cosf(radians)) + axis.values[0]*sinf(radians), 0 }," + "\n { axis.values[2]*axis.values[0]*(1 - cosf(radians)) + axis.values[1]*sinf(radians), axis.values[2]*axis.values[1]*(1 - cosf(radians)) - axis.values[0]*sinf(radians), cosf(radians) + axis.values[2]*axis.values[2]*(1 - cosf(radians)), 0 }," + "\n { 0, 0, 0, 1 }" + "\n }};" , suffix)); + for (int32_t i = 0; i < 4; ++i) { + for (int32_t j = 0; j < 4; ++j) { + cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", i, j)); + char *prefix = ""; + for (int32_t k = 0; k < 4; ++k) { + cb_gen_push(gen, cb_format("%s(rot.values[%d][%d]) * m.values[%d][%d]", + prefix, k, j, i, k)); + prefix = " + "; + } + cb_gen_push(gen, ";"); } - cb_gen_push(gen, ";"); } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); } static void -cb_linagen_defun_matnn_identity(CB_Generator *gen, char *type, - int32_t n, bool implementation) { +cb_linagen_defun_mat4_transform_scale(CB_Generator *gen, char *type, + bool implementation) { char *suffix = strdup(type); *suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_identity", - n, type)); - cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_transform_scale", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("Mat4%s m", suffix)); + cb_gen_push_func_arg(gen, cb_format("Vec3%s v", suffix)); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } cb_gen_push(gen, " {"); - cb_gen_push(gen, "\n memset(res, 0, sizeof *res);"); - for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = 1;", i, i)); + cb_gen_push(gen, cb_format("\n Mat4%s res = {0};" + "\n Mat4%s scale = {0};" + "\n scale.values[0][0] = v.values[0];" + "\n scale.values[1][1] = v.values[1];" + "\n scale.values[2][2] = v.values[2];" + "\n scale.values[3][3] = 1;", + suffix, suffix)); + for (int32_t i = 0; i < 4; ++i) { + for (int32_t j = 0; j < 4; ++j) { + cb_gen_push(gen, cb_format("\n res.values[%d][%d] = ", i, j)); + char *prefix = ""; + for (int32_t k = 0; k < 4; ++k) { + cb_gen_push(gen, cb_format("%s(scale.values[%d][%d]) * m.values[%d][%d]", + prefix, k, j, i, k)); + prefix = " + "; + } + cb_gen_push(gen, ";"); + } } - cb_gen_push(gen, "\n}\n\n"); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); } +static void +cb_linagen_defun_mat4_projection_orthographic(CB_Generator *gen, char *type, + bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_orthographic", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("%s left, %s right, %s bottom, %s top, %s near, %s far", + type, type, type, type, type, type)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } -internal void -cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type, - int32_t n, bool implementation, - char *func_name, char op) { - char *vec_suffix = strdup(type); - *vec_suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_%s", - n, type, func_name)); - cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, vec_suffix)); - cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v2", n, vec_suffix)); + cb_gen_push(gen, " {"); + cb_gen_push(gen, cb_format("\n Mat4%s res = {0};" + "\n res.values[0][0] = 2 / (right - left);" + "\n res.values[1][1] = 2 / (top - bottom);" + "\n res.values[2][2] = -2 / (far - near);" + "\n res.values[3][0] = -(right + left) / (right - left);" + "\n res.values[3][1] = -(top + bottom) / (top - bottom);" + "\n res.values[3][2] = -(far + near) / (far - near);" + "\n res.values[3][3] = 1;", + suffix, suffix)); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); +} + +static void +cb_linagen_defun_mat4_projection_perspective(CB_Generator *gen, char *type, + bool implementation) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat4%s mat4%s_projection_perspective", suffix, type)); + cb_gen_push_func_arg(gen, cb_format("float yfov_radians, float aspect_ratio, float near, float far")); cb_gen_push_func_end(gen, implementation); if (!implementation) { return; } cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] %c v2->values[%d];", - i, i, op, i)); + cb_gen_push(gen, cb_format("\n %s top = near * tanf(yfov_radians/2);" + "\n %s right = top * aspect_ratio;" + "\n Mat4%s res = {0};" + "\n res.arr[0] = near / right;" + "\n res.arr[5] = near / top;" + "\n res.arr[10] = -(far + near) / (far - near);" + "\n res.arr[11] = -1;" + "\n res.arr[14] = -(2 * far * near) / (far - near);", + type, type, suffix, suffix)); + cb_gen_push(gen, "\n return res;" "\n}\n\n"); +} + + +internal void +cb_linagen_defun_vecn_element_wise(CB_Generator *gen, char *type, + int32_t n, bool implementation, + char *func_name, char op) { + char *suffix = strdup(type); + *suffix = char_toupper(*type); + if (n <= CB_LINAGEN_VECN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Vec%d%s vec%d%s_%s", + n, suffix, n, type, func_name)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s v1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s v2", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n v1.values[%d] %c= v2.values[%d];", + i, op, i)); + } + cb_gen_push(gen, "\n return v1;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void vec%d%s_%s", + n, type, func_name)); + cb_gen_push_func_arg(gen, cb_format("Vec%d%s *res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Vec%d%s *v2", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + cb_gen_push(gen, cb_format("\n res->values[%d] = v1->values[%d] %c v2->values[%d];", + i, i, op, i)); + } + cb_gen_push(gen, "\n}\n\n"); } - cb_gen_push(gen, "\n}\n\n"); } internal void @@ -588,22 +954,40 @@ cb_linagen_defun_matnn_element_wise(CB_Generator *gen, char *type, char *func_name, char op) { char *suffix = strdup(type); *suffix = char_toupper(*type); - cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_%s", - n, type, func_name)); - cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m1", n, suffix)); - cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m2", n, suffix)); - cb_gen_push_func_end(gen, implementation); - if (!implementation) { return; } - - cb_gen_push(gen, " {"); - for (int32_t i = 0; i < n; ++i) { - for (int32_t j = 0; j < n; ++j) { - cb_gen_push(gen, cb_format("\n res->values[%d][%d] = m1->values[%d][%d] %c m2->values[%d][%d];", - i, j, i, j, op, i, j)); + if (n < CB_LINAGEN_MATNN_COPY_CAP) { + cb_gen_push_func_begin(gen, cb_format("linagen_fn Mat%d%s mat%d%s_%s", + n, suffix, n, type, func_name)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s m2", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, cb_format(" {" "\n Mat%d%s res = {0};", n, suffix)); + for (int32_t i = 0; i < n; ++i) { + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("\n res.values[%d][%d] = m1->values[%d][%d] %c m2->values[%d][%d];", + i, j, i, j, op, i, j)); + } } + cb_gen_push(gen, "\n return res;" "\n}\n\n"); + } else { + cb_gen_push_func_begin(gen, cb_format("linagen_fn void mat%d%s_%s", + n, type, func_name)); + cb_gen_push_func_arg(gen, cb_format("Mat%d%s *res", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m1", n, suffix)); + cb_gen_push_func_arg(gen, cb_format("const Mat%d%s *m2", n, suffix)); + cb_gen_push_func_end(gen, implementation); + if (!implementation) { return; } + + cb_gen_push(gen, " {"); + for (int32_t i = 0; i < n; ++i) { + for (int32_t j = 0; j < n; ++j) { + cb_gen_push(gen, cb_format("\n res->values[%d][%d] = m1->values[%d][%d] %c m2->values[%d][%d];", + i, j, i, j, op, i, j)); + } + } + cb_gen_push(gen, "\n}\n\n"); } - cb_gen_push(gen, "\n}\n\n"); } internal char char_toupper(char ch) { @@ -613,4 +997,6 @@ internal char char_toupper(char ch) { return ch; } +#undef MIN + #endif