src/ascension/datatypes.h

Sun, 06 Jul 2025 18:49:44 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 06 Jul 2025 18:49:44 +0200
changeset 186
e9bb4d4f88a8
parent 184
fe735cd266f3
child 187
15763968dfd5
permissions
-rw-r--r--

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

mercurial