Browse Source

Add clamp functions

rexim 4 years ago
parent
commit
bc02ea062d
2 changed files with 150 additions and 1 deletions
  1. 99 0
      la.h
  2. 51 1
      lag.c

+ 99 - 0
la.h

@@ -11,6 +11,9 @@ LADEF float lerpf(float a, float b, float t);
 LADEF double lerp(double a, double b, double t);
 LADEF int mini(int a, int b);
 LADEF int maxi(int a, int b);
+LADEF float clampf(float x, float a, float b);
+LADEF double clampd(double x, double a, double b);
+LADEF int clampi(int x, int a, int b);
 
 typedef struct { float x, y; } V2f;
 typedef struct { double x, y; } V2d;
@@ -47,6 +50,7 @@ LADEF V2f v2f_max(V2f a, V2f b);
 LADEF V2f v2f_lerp(V2f a, V2f b, V2f t);
 LADEF V2f v2f_floor(V2f a);
 LADEF V2f v2f_ceil(V2f a);
+LADEF V2f v2f_clamp(V2f x, V2f a, V2f b);
 LADEF float v2f_sqrlen(V2f a);
 LADEF float v2f_len(V2f a);
 
@@ -75,6 +79,7 @@ LADEF V2d v2d_max(V2d a, V2d b);
 LADEF V2d v2d_lerp(V2d a, V2d b, V2d t);
 LADEF V2d v2d_floor(V2d a);
 LADEF V2d v2d_ceil(V2d a);
+LADEF V2d v2d_clamp(V2d x, V2d a, V2d b);
 LADEF double v2d_sqrlen(V2d a);
 LADEF double v2d_len(V2d a);
 
@@ -96,6 +101,7 @@ LADEF V2i v2i_mul(V2i a, V2i b);
 LADEF V2i v2i_div(V2i a, V2i b);
 LADEF V2i v2i_min(V2i a, V2i b);
 LADEF V2i v2i_max(V2i a, V2i b);
+LADEF V2i v2i_clamp(V2i x, V2i a, V2i b);
 LADEF int v2i_sqrlen(V2i a);
 
 #define V3f_Fmt "v3f(%f, %f, %f)"
@@ -123,6 +129,7 @@ LADEF V3f v3f_max(V3f a, V3f b);
 LADEF V3f v3f_lerp(V3f a, V3f b, V3f t);
 LADEF V3f v3f_floor(V3f a);
 LADEF V3f v3f_ceil(V3f a);
+LADEF V3f v3f_clamp(V3f x, V3f a, V3f b);
 LADEF float v3f_sqrlen(V3f a);
 LADEF float v3f_len(V3f a);
 
@@ -151,6 +158,7 @@ LADEF V3d v3d_max(V3d a, V3d b);
 LADEF V3d v3d_lerp(V3d a, V3d b, V3d t);
 LADEF V3d v3d_floor(V3d a);
 LADEF V3d v3d_ceil(V3d a);
+LADEF V3d v3d_clamp(V3d x, V3d a, V3d b);
 LADEF double v3d_sqrlen(V3d a);
 LADEF double v3d_len(V3d a);
 
@@ -172,6 +180,7 @@ LADEF V3i v3i_mul(V3i a, V3i b);
 LADEF V3i v3i_div(V3i a, V3i b);
 LADEF V3i v3i_min(V3i a, V3i b);
 LADEF V3i v3i_max(V3i a, V3i b);
+LADEF V3i v3i_clamp(V3i x, V3i a, V3i b);
 LADEF int v3i_sqrlen(V3i a);
 
 #define V4f_Fmt "v4f(%f, %f, %f, %f)"
@@ -199,6 +208,7 @@ LADEF V4f v4f_max(V4f a, V4f b);
 LADEF V4f v4f_lerp(V4f a, V4f b, V4f t);
 LADEF V4f v4f_floor(V4f a);
 LADEF V4f v4f_ceil(V4f a);
+LADEF V4f v4f_clamp(V4f x, V4f a, V4f b);
 LADEF float v4f_sqrlen(V4f a);
 LADEF float v4f_len(V4f a);
 
@@ -227,6 +237,7 @@ LADEF V4d v4d_max(V4d a, V4d b);
 LADEF V4d v4d_lerp(V4d a, V4d b, V4d t);
 LADEF V4d v4d_floor(V4d a);
 LADEF V4d v4d_ceil(V4d a);
+LADEF V4d v4d_clamp(V4d x, V4d a, V4d b);
 LADEF double v4d_sqrlen(V4d a);
 LADEF double v4d_len(V4d a);
 
@@ -248,6 +259,7 @@ LADEF V4i v4i_mul(V4i a, V4i b);
 LADEF V4i v4i_div(V4i a, V4i b);
 LADEF V4i v4i_min(V4i a, V4i b);
 LADEF V4i v4i_max(V4i a, V4i b);
+LADEF V4i v4i_clamp(V4i x, V4i a, V4i b);
 LADEF int v4i_sqrlen(V4i a);
 
 #endif // LA_H_
@@ -274,6 +286,21 @@ LADEF int maxi(int a, int b)
     return a < b ? b : a;
 }
 
+LADEF float clampf(float x, float a, float b)
+{
+    return fminf(fmaxf(a, x), b);
+}
+
+LADEF double clampd(double x, double a, double b)
+{
+    return fmin(fmax(a, x), b);
+}
+
+LADEF int clampi(int x, int a, int b)
+{
+    return mini(maxi(a, x), b);
+}
+
 LADEF V2f v2f(float x, float y)
 {
     V2f v;
@@ -442,6 +469,13 @@ LADEF V2f v2f_ceil(V2f a)
     return a;
 }
 
+LADEF V2f v2f_clamp(V2f x, V2f a, V2f b)
+{
+    x.x = clampf(x.x, a.x, b.x);
+    x.y = clampf(x.y, a.y, b.y);
+    return x;
+}
+
 LADEF float v2f_sqrlen(V2f a)
 {
     return a.x*a.x + a.y*a.y;
@@ -620,6 +654,13 @@ LADEF V2d v2d_ceil(V2d a)
     return a;
 }
 
+LADEF V2d v2d_clamp(V2d x, V2d a, V2d b)
+{
+    x.x = clampd(x.x, a.x, b.x);
+    x.y = clampd(x.y, a.y, b.y);
+    return x;
+}
+
 LADEF double v2d_sqrlen(V2d a)
 {
     return a.x*a.x + a.y*a.y;
@@ -749,6 +790,13 @@ LADEF V2i v2i_max(V2i a, V2i b)
     return a;
 }
 
+LADEF V2i v2i_clamp(V2i x, V2i a, V2i b)
+{
+    x.x = clampi(x.x, a.x, b.x);
+    x.y = clampi(x.y, a.y, b.y);
+    return x;
+}
+
 LADEF int v2i_sqrlen(V2i a)
 {
     return a.x*a.x + a.y*a.y;
@@ -944,6 +992,14 @@ LADEF V3f v3f_ceil(V3f a)
     return a;
 }
 
+LADEF V3f v3f_clamp(V3f x, V3f a, V3f b)
+{
+    x.x = clampf(x.x, a.x, b.x);
+    x.y = clampf(x.y, a.y, b.y);
+    x.z = clampf(x.z, a.z, b.z);
+    return x;
+}
+
 LADEF float v3f_sqrlen(V3f a)
 {
     return a.x*a.x + a.y*a.y + a.z*a.z;
@@ -1144,6 +1200,14 @@ LADEF V3d v3d_ceil(V3d a)
     return a;
 }
 
+LADEF V3d v3d_clamp(V3d x, V3d a, V3d b)
+{
+    x.x = clampd(x.x, a.x, b.x);
+    x.y = clampd(x.y, a.y, b.y);
+    x.z = clampd(x.z, a.z, b.z);
+    return x;
+}
+
 LADEF double v3d_sqrlen(V3d a)
 {
     return a.x*a.x + a.y*a.y + a.z*a.z;
@@ -1288,6 +1352,14 @@ LADEF V3i v3i_max(V3i a, V3i b)
     return a;
 }
 
+LADEF V3i v3i_clamp(V3i x, V3i a, V3i b)
+{
+    x.x = clampi(x.x, a.x, b.x);
+    x.y = clampi(x.y, a.y, b.y);
+    x.z = clampi(x.z, a.z, b.z);
+    return x;
+}
+
 LADEF int v3i_sqrlen(V3i a)
 {
     return a.x*a.x + a.y*a.y + a.z*a.z;
@@ -1505,6 +1577,15 @@ LADEF V4f v4f_ceil(V4f a)
     return a;
 }
 
+LADEF V4f v4f_clamp(V4f x, V4f a, V4f b)
+{
+    x.x = clampf(x.x, a.x, b.x);
+    x.y = clampf(x.y, a.y, b.y);
+    x.z = clampf(x.z, a.z, b.z);
+    x.w = clampf(x.w, a.w, b.w);
+    return x;
+}
+
 LADEF float v4f_sqrlen(V4f a)
 {
     return a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;
@@ -1727,6 +1808,15 @@ LADEF V4d v4d_ceil(V4d a)
     return a;
 }
 
+LADEF V4d v4d_clamp(V4d x, V4d a, V4d b)
+{
+    x.x = clampd(x.x, a.x, b.x);
+    x.y = clampd(x.y, a.y, b.y);
+    x.z = clampd(x.z, a.z, b.z);
+    x.w = clampd(x.w, a.w, b.w);
+    return x;
+}
+
 LADEF double v4d_sqrlen(V4d a)
 {
     return a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;
@@ -1886,6 +1976,15 @@ LADEF V4i v4i_max(V4i a, V4i b)
     return a;
 }
 
+LADEF V4i v4i_clamp(V4i x, V4i a, V4i b)
+{
+    x.x = clampi(x.x, a.x, b.x);
+    x.y = clampi(x.y, a.y, b.y);
+    x.z = clampi(x.z, a.z, b.z);
+    x.w = clampi(x.w, a.w, b.w);
+    return x;
+}
+
 LADEF int v4i_sqrlen(V4i a)
 {
     return a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w;

+ 51 - 1
lag.c

@@ -221,6 +221,7 @@ typedef enum {
     FUN_LERP,
     FUN_FLOOR,
     FUN_CEIL,
+    FUN_CLAMP,
     COUNT_FUNS,
 } Fun_Type;
 
@@ -234,7 +235,7 @@ typedef struct {
     char *args[FUN_DEF_MAX_ARITY];
 } Fun_Def;
 
-static_assert(COUNT_FUNS == 9, "The amount of functions have changed. Please update the array below accordingly");
+static_assert(COUNT_FUNS == 10, "The amount of functions have changed. Please update the array below accordingly");
 static_assert(COUNT_TYPES == 3, "The amount of type definitions have changed. Please update the array bellow accordingly");
 Fun_Def fun_defs[COUNT_FUNS] = {
     [FUN_SQRT] = {
@@ -319,6 +320,16 @@ Fun_Def fun_defs[COUNT_FUNS] = {
         },
         .arity = 1,
         .args = {"a"},
+    },
+    [FUN_CLAMP] = {
+        .suffix = "clamp",
+        .name_for_type = {
+            [TYPE_FLOAT] = "clampf",
+            [TYPE_DOUBLE] = "clampd",
+            [TYPE_INT] = "clampi",
+        },
+        .arity = 3,
+        .args = {"x", "a", "b"}
     }
 };
 
@@ -422,6 +433,38 @@ void gen_max_impl(FILE *stream, const char *name, const char *type)
     fprintf(stream, "}\n");
 }
 
+char *clamp_args[] = {"x", "a", "b"};
+#define CLAMP_ARITY (sizeof(clamp_args) / sizeof(clamp_args[0]))
+
+void gen_clamp_sig(FILE *stream, Type_Def type_def)
+{
+    Short_String name = shortf("clamp%s", type_def.suffix);
+    gen_func_sig(stream, type_def.name, name.cstr, type_def.name, clamp_args, CLAMP_ARITY);
+}
+
+void gen_clamp_decl(FILE *stream, Type_Def type_def)
+{
+    gen_clamp_sig(stream, type_def);
+    fprintf(stream, ";\n");
+}
+
+void gen_clamp_impl(FILE *stream, Type type, Fun_Def min_def, Fun_Def max_def)
+{
+    Type_Def type_def = type_defs[type];
+    const char *min_name = min_def.name_for_type[type];
+    assert(min_name != NULL);
+    const char *max_name = max_def.name_for_type[type];
+    assert(max_name != NULL);
+
+    gen_clamp_sig(stream, type_def);
+    fprintf(stream, "\n");
+    fprintf(stream, "{\n");
+    static_assert(CLAMP_ARITY == 3, "Unexpected clamp arity");
+    fprintf(stream, "    return %s(%s(%s, %s), %s);\n", 
+            min_name, max_name, clamp_args[1], clamp_args[0], clamp_args[2]);
+    fprintf(stream, "}\n");
+}
+
 static char *sqrlen_arg_name = "a";
 
 void gen_vector_sqrlen_sig(FILE *stream, size_t n, Type_Def type_def)
@@ -570,6 +613,9 @@ int main()
         gen_lerp_decl(stream, "lerp", "double");
         gen_minmax_decl(stream, "mini", "int");
         gen_minmax_decl(stream, "maxi", "int");
+        for (Type type = 0; type < COUNT_TYPES; ++type) {
+            gen_clamp_decl(stream, type_defs[type]);
+        }
         fprintf(stream, "\n");
         for (size_t n = VECTOR_MIN_SIZE; n <= VECTOR_MAX_SIZE; ++n) {
             for (Type type = 0; type < COUNT_TYPES; ++type) {
@@ -622,6 +668,10 @@ int main()
         fputc('\n', stream);
         gen_max_impl(stream, "maxi", "int");
         fputc('\n', stream);
+        for (Type type = 0; type < COUNT_TYPES; ++type) {
+            gen_clamp_impl(stream, type, fun_defs[FUN_MIN], fun_defs[FUN_MAX]);
+            fputc('\n', stream);
+        }
         for (size_t n = VECTOR_MIN_SIZE; n <= VECTOR_MAX_SIZE; ++n) {
             for (Type type = 0; type < COUNT_TYPES; ++type) {
                 gen_vector_ctor_impl(stream, n, type_defs[type]);