Sun, 06 Jul 2025 18:49:44 +0200
rename asc_recti to just asc_rect (there won't be an asc_rectu)
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * Copyright 2023 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef ASCENSION_DATATYPES_H #define ASCENSION_DATATYPES_H #ifdef __cplusplus #error You cannot ascend using C++ #endif #include <stdbool.h> #include <string.h> #include <SDL2/SDL_pixels.h> // -------------------------------------------------------------------------- // Useful Macros // -------------------------------------------------------------------------- #define asc_nanoseconds(t) (t) #define asc_microseconds(t) (t*1000ull) #define asc_milliseconds(t) (t*1000000ull) #define asc_seconds(t) (t*1000000000ull) /** * Tests a value if it is zero and returns an alternative when it is. * * @param y the alternative * @param x the value that shall be tested * @return x if nonzero, y otherwise */ #define ASC_NONZERO_OR(y, x) ((x) != 0 ? x : y) #define asc_test_flag(reg, flag) ((reg & flag) == flag) #define asc_test_flag_masked(reg, mask, flag) ((reg & mask) == flag) #define asc_clear_flag(reg, flag) (reg &= ~(flag)) #define asc_set_flag(reg, flag) (reg |= flag) #define asc_set_flag_masked(reg, mask, flag) (reg = (reg & ~(mask)) | flag) #define asc_ptr_cast(type, lvalue, rvalue) type *lvalue = (type *)(rvalue); #define asc_cptr_cast(type, lvalue, rvalue) const type *lvalue = (const type *)(rvalue); // -------------------------------------------------------------------------- // Datatype Definitions // -------------------------------------------------------------------------- typedef unsigned char asc_ubyte; typedef signed char asc_sbyte; typedef union asc_vec2i { struct { int x, y; }; struct { int width, height; }; int data[2]; } asc_vec2i; #define ASC_VEC2I(x, y) (asc_vec2i){{(int)x, (int)y}} #define ASC_VEC2I_0 (asc_vec2i){{0, 0}} #define ASC_VEC2I_1 (asc_vec2i){{1, 1}} typedef union asc_vec2u { struct { unsigned x, y; }; struct { unsigned width, height; }; unsigned data[2]; } asc_vec2u; #define ASC_VEC2U(x, y) (asc_vec2u){{(unsigned)x, (unsigned)y}} #define ASC_VEC2U_0 (asc_vec2u){{0u, 0u}} #define ASC_VEC2U_1 (asc_vec2u){{1u, 1u}} typedef struct asc_rect { asc_vec2i pos; asc_vec2u size; } asc_rect; #define ASC_RECT(x, y, w, h) (asc_rect){ASC_VEC2I(x,y), ASC_VEC2U(w,h)} typedef union asc_vec2f { struct { float x, y; }; struct { float width, height; }; struct { float u, v; }; float data[2]; } asc_vec2f; #define ASC_VEC2F(x, y) (asc_vec2f){{(float)x, (float)y}} #define ASC_VEC2F_0 (asc_vec2f){{0.0f, 0.0f}} #define ASC_VEC2F_1 (asc_vec2f){{1.0f, 1.0f}} typedef union asc_vec3f { struct { float x, y, z; }; struct { float width, height, depth; }; struct { float pitch, yaw, roll; }; float data[3]; } asc_vec3f; #define ASC_VEC3F(x, y, z) (asc_vec3f){{(float)x, (float)y, (float)(z)}} #define ASC_VEC3F_0 (asc_vec3f){{0.0f, 0.0f, 0.0f}} #define ASC_VEC3F_1 (asc_vec3f){{1.0f, 1.0f, 1.0f}} typedef struct asc_col4i { asc_ubyte red, green, blue, alpha; } asc_col4i; typedef struct asc_col4f { float red, green, blue, alpha; } asc_col4f; #define ASC_RGB(r,g,b) (asc_col4i){(asc_ubyte)r, (asc_ubyte)g, (asc_ubyte)b, 255u} #define ASC_RGBA(r,g,b,a) (asc_col4i){(asc_ubyte)r, (asc_ubyte)g, (asc_ubyte)b, (asc_ubyte)a} #define ASC_RGB_F(r,g,b) (asc_col4f){r,g,b,1.f} #define ASC_RGBA_F(r,g,b,a) (asc_col4f){r,g,b,a} typedef float asc_mat4f[16]; // -------------------------------------------------------------------------- // General Utility Functions // -------------------------------------------------------------------------- static inline bool asc_memcmpz(const void *mem, size_t n) { const unsigned char *p = mem; // TODO: for some reason this is not vectorized - find out why! for (size_t i = 0; i < n ; i++) { if (p[i]>0) return false; } return true; } static inline int asc_clamp_i(int v, int min, int max) { if (v < min) return min; if (v > max) return max; return v; } static inline unsigned asc_clamp_u(unsigned v, unsigned min, unsigned max) { if (v < min) return min; if (v > max) return max; return v; } static inline asc_vec2i asc_rect_center(asc_rect rect) { return ASC_VEC2I(rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2); } /** * Converts a float color (0.0f to 1.0f) to an int color (0 to 255). * * This operation is quite expensive. When you need to use it often, it's * quite obvious that you should change the data type. * * @param c the color using floats * @return the same color using ints */ static inline asc_col4i asc_col_ftoi(asc_col4f c) { unsigned red = (unsigned)(255*c.red); unsigned green = (unsigned)(255*c.green); unsigned blue = (unsigned)(255*c.blue); unsigned alpha = (unsigned)(255*c.alpha); asc_col4i r; r.red = asc_clamp_u(red, 0, 255); r.green = asc_clamp_u(green, 0, 255); r.blue = asc_clamp_u(blue, 0, 255); r.alpha = asc_clamp_u(alpha, 0, 255); return r; } static inline asc_col4f asc_col_itof(asc_col4i c) { // dividing by 256 is much more performant // because it compiles to multiplication instead of division const float f = 256.f / 255.f; const float red = c.red * f / 256.f; const float green = c.green * f / 256.f; const float blue = c.blue * f / 256.f; const float alpha = c.alpha * f / 256.f; return (asc_col4f) {red, green, blue, alpha}; } static inline SDL_Color asc_col_sdl(asc_col4i col) { return (SDL_Color) {.r = col.red, .g = col.green, .b = col.blue, .a = col.alpha}; } // -------------------------------------------------------------------------- // Vector Functions // -------------------------------------------------------------------------- static inline asc_vec2f asc_vec2f_scale(asc_vec2f v, float s) { return ASC_VEC2F(v.x*s, v.y*s); } static inline asc_vec3f asc_vec3f_scale(asc_vec3f v, float s) { return ASC_VEC3F(v.x*s, v.y*s, v.z*s); } static inline unsigned asc_vec2u_sqrlen(asc_vec2u v) { return v.x*v.x + v.y*v.y; } static inline unsigned asc_vec2i_sqrlen(asc_vec2i v) { return v.x*v.x + v.y*v.y; } static inline float asc_vec2f_sqrlen(asc_vec2f v) { return v.x*v.x + v.y*v.y; } static inline float asc_vec3f_sqrlen(asc_vec3f v) { return v.x*v.x + v.y*v.y + v.z*v.z; } // -------------------------------------------------------------------------- // Matrix Functions // -------------------------------------------------------------------------- /** * Computes a matrix index in column-major order. * @param col the column * @param row the row * @param rows the number of rows */ #define asc_mat_index(col, row, rows) ((row) + (col) * (rows)) /** * Computes a 4x4 matrix index in column-major order. * @param col the column * @param row the row */ #define asc_mat4_index(col, row) asc_mat_index(col, row, 4) static inline void asc_mat4f_unit(asc_mat4f mat) { memset(mat, 0, sizeof(float) * 16); mat[asc_mat4_index(0,0)] = 1; mat[asc_mat4_index(1,1)] = 1; mat[asc_mat4_index(2,2)] = 1; mat[asc_mat4_index(3,3)] = 1; } static inline void asc_mat4f_ortho( asc_mat4f mat, float left, float right, float bottom, float top, float near, float far ) { memset(mat, 0, sizeof(float) * 16); mat[asc_mat4_index(0,0)] = 2.f / (right - left); mat[asc_mat4_index(1,1)] = 2.f / (top - bottom); mat[asc_mat4_index(2,2)] = -2.f / (far - near); mat[asc_mat4_index(3,0)] = -(right + left) / (right - left); mat[asc_mat4_index(3,1)] = -(top + bottom) / (top - bottom); mat[asc_mat4_index(3,2)] = -(far + near) / (far - near); mat[asc_mat4_index(3,3)] = 1; } /** * Shorter version of updating an orthographic matrix which assumes the top right corner at (0,0). * * @attention The matrix MUST have been properly initialized with asc_mat4f_ortho() with left=0 and top=0, first! * * @param mat the matrix * @param width the new width (right coordinate) * @param height the new height (bottom coordinate) */ static inline void asc_mat4f_ortho_update_size( asc_mat4f mat, float width, float height ) { mat[asc_mat4_index(0,0)] = 2.f / width; mat[asc_mat4_index(1,1)] = -2.f / height; } static inline void asc_mat4f_mulst( asc_mat4f dest, asc_mat4f const left, asc_mat4f const right ) { for (unsigned i = 0; i < 4; i++) { for (unsigned j = 0; j < 4; j++) { dest[asc_mat4_index(i, j)] = 0; for (int k = 0; k < 4; k++) { dest[asc_mat4_index(i,j)] += left[asc_mat4_index(i,k)] * right[asc_mat4_index(k,j)]; } } } } #endif //ASCENSION_DATATYPES_H