#ifndef DEFOCUS_BASE_H #define DEFOCUS_BASE_H #include #include #include /** @file base.h * @brief basic utilities */ /** @brief Result codes used throughout the codebase */ typedef enum { /** @brief operation successfull */ df_result_success = 0, /** @brief memory allocation failed */ df_result_out_of_memory = 1, /** @brief file i/o error */ df_result_io_error = 2, } df_result; /** @brief Used to silence warnings about unused variables */ #define DF_UNUSED(x) ((void)sizeof((x))) /** @brief Evaluates to the number of elements in a static array. */ #define DF_ARRAY_COUNT(a) (sizeof((a)) / sizeof((a)[0])) /** @brief Zero a memory range */ #define DF_ZERO_MEMORY(ptr, n) memset((ptr), 0, (n)) /** @brief Zero a struct */ #define DF_ZERO_STRUCT(ptr) DF_ZERO_MEMORY(ptr, sizeof(*(ptr))) /** @brief Zero an array */ #define DF_ZERO_ARRAY(a, n) DF_ZERO_MEMORY(a, sizeof((a)[0]) * (n)) #ifdef _MSC_VER #ifdef __cplusplus__ #define DF_API extern "C" __declspec(dllexport) #else #define DF_API __declspec(dllexport) #endif /* _MSC_VER && __cplusplus__ */ #else #ifdef __cplusplus__ #define DF_API extern "C" #else #define DF_API #endif #endif /* Simple logging function */ #ifndef DF_ENABLE_LOGGING #define DF_ENABLE_LOGGING 1 #endif enum { df_log_level_verbose = 0, df_log_level_info = 1, df_log_level_warn = 2, df_log_level_error = 3, }; #if DF_ENABLE_LOGGING /** @brief The actual log implementation. * * There should be no need to call this directly. * * Instead use one of: * - df_log_verbose() * - df_log_info() * - df_log_warn() * - df_log_error() * @param level the log level. Used to filter the messages. * @param file file name of the log location * @param line line number of the log location * @param fmt format string of the message. */ DF_API void df_log_impl(int level, const char *file, int line, const char *fmt, ...); #define df_log_verbose(...) df_log_impl(df_log_level_verbose, __FILE__, __LINE__, __VA_ARGS__) #define df_log_info(...) df_log_impl(df_log_level_info, __FILE__, __LINE__, __VA_ARGS__) #define df_log_warn(...) df_log_impl(df_log_level_warn, __FILE__, __LINE__, __VA_ARGS__) #define df_log_error(...) df_log_impl(df_log_level_error, __FILE__, __LINE__, __VA_ARGS__) #else /* DF_ENABLE_LOGGING = 0 */ #define df_log_verbose(fmt, ...) #define df_log_info(fmt, ...) #define df_log_warn(fmt, ...) #define df_log_error(fmt, ...) #endif /* Math constants. */ #define DF_PI 3.1415926f #define DF_PI_OVER_2 1.570796f #define DF_PI_OVER_4 0.785398f /* Basic types */ /** @brief RGBA color */ typedef union { struct { uint8_t r; uint8_t g; uint8_t b; uint8_t a; }; uint8_t e[4]; } df_color; /** @brief Linear interpolation between two colors. * * @param a first color * @param b second color * @param t interpolation factor * @return a + (b - a) * t */ DF_API df_color df_lerp_color(df_color a, df_color b, double t); /** @brief 2d vector */ typedef union { struct { float x; float y; }; struct { float u; float v; }; float e[2]; } df_v2; /** @brief Add two 2d vectors */ DF_API df_v2 df_add_v2(df_v2 a, df_v2 b); /** @brief Subtract two 2d vectors */ DF_API df_v2 df_sub_v2(df_v2 a, df_v2 b); /** @brief Calculate the dot product of 2d vectors a and b. */ DF_API float df_dot_v2(df_v2 a, df_v2 b); /** @brief Multiply a 2d vector with a scalar. */ DF_API df_v2 df_mul_v2(float t, df_v2 v); /** @brief Returns the normalized version of a 2d vector v */ DF_API df_v2 df_normalize_v2(df_v2 v); /** @brief 3d vector */ typedef union { struct { float x; float y; float z; }; float e[3]; } df_v3; /** @brief Add two 3d vectors */ DF_API df_v3 df_add_v3(df_v3 a, df_v3 b); /** @brief Subtract two 3d vectors */ DF_API df_v3 df_sub_v3(df_v3 a, df_v3 b); /** @brief Calculate the dot product of 3d vectors a and b. */ DF_API float df_dot_v3(df_v3 a, df_v3 b); /** @brief Multiply a 3d vector with a scalar. */ DF_API df_v3 df_mul_v3(float t, df_v3 v); /** @brief Returns the normalized version of a 3d vector v */ DF_API df_v3 df_normalize_v3(df_v3 v); /** @brief A plane in 3d space. * * Expressed as the set of all points p for which * dot((p - base), normal) = 0 */ typedef struct { df_v3 base; df_v3 normal; } df_plane; /** @brief A line in 3d space. * * Expressed as the vector equation p = base + t * direction. */ typedef struct { df_v3 base; df_v3 direction; } df_line; /** @brief The three possible result types of a line-plane intersection test. */ typedef enum { /** The line and plane intersect in one point */ df_line_plane_intersection_vector, /** The line is contained in the plane */ df_line_plane_intersection_contained, /** The line and plane don't intersect (-> they are parallel) */ df_line_plane_intersection_none, } df_line_plane_intersection_type; /** @brief Result of a line-plane intersection test. * The contained vector is only valid if @c type = @c df_line_plane_intersection_vector. */ typedef struct { df_line_plane_intersection_type type; df_v3 vec; } df_line_plane_intersection; /** @brief Calculate the intersection between a line and a plane in 3d space */ DF_API df_line_plane_intersection df_calc_line_plane_intersection(df_line line, df_plane plane); /** @brief A 4x4 matrix. * * Stored in row major order. */ typedef struct df_m4 { _Alignas(16) union { float e[16]; __m128 vec[4]; }; } df_m4; /** Accesses the element at the given row and column of a 4x4 matrix */ #define DF_M4_AT(m, row, col) ((m).e[(row)*4 + (col)]) /** @brief Matrix multiply 4x4 matrix a and b */ DF_API df_m4 df_mul_m4(df_m4 a, df_m4 b); /** @brief Get a scale matrix */ DF_API df_m4 df_scale(float x, float y, float z); DF_API df_m4 df_translate(float x, float y, float z); /** @brief Transform (i.e. multiply) a 3d vector v by the transformation matrix T */ DF_API df_v3 df_transform_v3(df_m4 T, df_v3 v); /** @brief Calculate the inverse of a non-scaling transform matrix. * * Special fast case. */ DF_API df_m4 df_inverse_transform_no_scale(df_m4 M); /** @brief Calculate the inverse of a transform matrix */ DF_API df_m4 df_inverse_transform(df_m4 M); /** @brief Calculate the inverse of a general (invertible) 4x4 matrix */ DF_API df_m4 df_inverse(df_m4 M); #endif