]> git.leonardobizzoni.com Git - CBuild/commitdiff
linear algebra generator changes
authorLeonardoBizzoni <leo2002714@gmail.com>
Thu, 6 Nov 2025 13:41:47 +0000 (14:41 +0100)
committerLeonardoBizzoni <leo2002714@gmail.com>
Thu, 6 Nov 2025 13:41:47 +0000 (14:41 +0100)
cbuild.h
extra/cbuild_codegen.h
extra/cbuild_linagen.h

index 14e2a1d78b598a215c422c0f1815463dc3d0a11e..c93ad1fb82b8190291aed0cd2a79176060f2d859 100644 (file)
--- 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;
index 88855f28e1aefcd570e33dea988b11a537a36746..1eca80e59c7d75dffc7dd6ab326cd6f003d22595 100644 (file)
@@ -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);
index 5f6a7964bcb133f5eb54d9c7f1d2ff4e8ae9e963..707162b55dc28086136258f3790f342fb2f8dadd 100644 (file)
@@ -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 <math.h>
 #include <stdarg.h>
 
 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