Blame src-nuklear/nuklear_math.c

Ivan Mahonin b53a5c
#include "nuklear.h"
Ivan Mahonin b53a5c
#include "nuklear_internal.h"
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
/* ===============================================================
Ivan Mahonin b53a5c
 *
Ivan Mahonin b53a5c
 *                              MATH
Ivan Mahonin b53a5c
 *
Ivan Mahonin b53a5c
 * ===============================================================*/
Ivan Mahonin b53a5c
/*/// ### Math
Ivan Mahonin b53a5c
///  Since nuklear is supposed to work on all systems providing floating point
Ivan Mahonin b53a5c
///  math without any dependencies I also had to implement my own math functions
Ivan Mahonin b53a5c
///  for sqrt, sin and cos. Since the actual highly accurate implementations for
Ivan Mahonin b53a5c
///  the standard library functions are quite complex and I do not need high
Ivan Mahonin b53a5c
///  precision for my use cases I use approximations.
Ivan Mahonin b53a5c
///
Ivan Mahonin b53a5c
///  Sqrt
Ivan Mahonin b53a5c
///  ----
Ivan Mahonin b53a5c
///  For square root nuklear uses the famous fast inverse square root:
Ivan Mahonin b53a5c
///  https://en.wikipedia.org/wiki/Fast_inverse_square_root with
Ivan Mahonin b53a5c
///  slightly tweaked magic constant. While on today's hardware it is
Ivan Mahonin b53a5c
///  probably not faster it is still fast and accurate enough for
Ivan Mahonin b53a5c
///  nuklear's use cases. IMPORTANT: this requires float format IEEE 754
Ivan Mahonin b53a5c
///
Ivan Mahonin b53a5c
///  Sine/Cosine
Ivan Mahonin b53a5c
///  -----------
Ivan Mahonin b53a5c
///  All constants inside both function are generated Remez's minimax
Ivan Mahonin b53a5c
///  approximations for value range 0...2*PI. The reason why I decided to
Ivan Mahonin b53a5c
///  approximate exactly that range is that nuklear only needs sine and
Ivan Mahonin b53a5c
///  cosine to generate circles which only requires that exact range.
Ivan Mahonin b53a5c
///  In addition I used Remez instead of Taylor for additional precision:
Ivan Mahonin b53a5c
///  www.lolengine.net/blog/2011/12/21/better-function-approximations.
Ivan Mahonin b53a5c
///
Ivan Mahonin b53a5c
///  The tool I used to generate constants for both sine and cosine
Ivan Mahonin b53a5c
///  (it can actually approximate a lot more functions) can be
Ivan Mahonin b53a5c
///  found here: www.lolengine.net/wiki/oss/lolremez
Ivan Mahonin b53a5c
*/
Ivan Mahonin b53a5c
#ifndef NK_INV_SQRT
Ivan Mahonin b53a5c
#define NK_INV_SQRT nk_inv_sqrt
Ivan Mahonin b53a5c
NK_LIB float
Ivan Mahonin b53a5c
nk_inv_sqrt(float n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    float x2;
Ivan Mahonin b53a5c
    const float threehalfs = 1.5f;
Ivan Mahonin b53a5c
    union {nk_uint i; float f;} conv = {0};
Ivan Mahonin b53a5c
    conv.f = n;
Ivan Mahonin b53a5c
    x2 = n * 0.5f;
Ivan Mahonin b53a5c
    conv.i = 0x5f375A84 - (conv.i >> 1);
Ivan Mahonin b53a5c
    conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
Ivan Mahonin b53a5c
    return conv.f;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
#ifndef NK_SIN
Ivan Mahonin b53a5c
#define NK_SIN nk_sin
Ivan Mahonin b53a5c
NK_LIB float
Ivan Mahonin b53a5c
nk_sin(float x)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    NK_STORAGE const float a0 = +1.91059300966915117e-31f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a1 = +1.00086760103908896f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a2 = -1.21276126894734565e-2f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a3 = -1.38078780785773762e-1f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a4 = -2.67353392911981221e-2f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a5 = +2.08026600266304389e-2f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a6 = -3.03996055049204407e-3f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a7 = +1.38235642404333740e-4f;
Ivan Mahonin b53a5c
    return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
#ifndef NK_COS
Ivan Mahonin b53a5c
#define NK_COS nk_cos
Ivan Mahonin b53a5c
NK_LIB float
Ivan Mahonin b53a5c
nk_cos(float x)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    /* New implementation. Also generated using lolremez. */
Ivan Mahonin b53a5c
    /* Old version significantly deviated from expected results. */
Ivan Mahonin b53a5c
    NK_STORAGE const float a0 = 9.9995999154986614e-1f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a1 = 1.2548995793001028e-3f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a2 = -5.0648546280678015e-1f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a3 = 1.2942246466519995e-2f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a4 = 2.8668384702547972e-2f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a5 = 7.3726485210586547e-3f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a6 = -3.8510875386947414e-3f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a7 = 4.7196604604366623e-4f;
Ivan Mahonin b53a5c
    NK_STORAGE const float a8 = -1.8776444013090451e-5f;
Ivan Mahonin b53a5c
    return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
#endif
Ivan Mahonin b53a5c
NK_LIB nk_uint
Ivan Mahonin b53a5c
nk_round_up_pow2(nk_uint v)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    v--;
Ivan Mahonin b53a5c
    v |= v >> 1;
Ivan Mahonin b53a5c
    v |= v >> 2;
Ivan Mahonin b53a5c
    v |= v >> 4;
Ivan Mahonin b53a5c
    v |= v >> 8;
Ivan Mahonin b53a5c
    v |= v >> 16;
Ivan Mahonin b53a5c
    v++;
Ivan Mahonin b53a5c
    return v;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB double
Ivan Mahonin b53a5c
nk_pow(double x, int n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    /*  check the sign of n */
Ivan Mahonin b53a5c
    double r = 1;
Ivan Mahonin b53a5c
    int plus = n >= 0;
Ivan Mahonin b53a5c
    n = (plus) ? n : -n;
Ivan Mahonin b53a5c
    while (n > 0) {
Ivan Mahonin b53a5c
        if ((n & 1) == 1)
Ivan Mahonin b53a5c
            r *= x;
Ivan Mahonin b53a5c
        n /= 2;
Ivan Mahonin b53a5c
        x *= x;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    return plus ? r : 1.0 / r;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB int
Ivan Mahonin b53a5c
nk_ifloord(double x)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    x = (double)((int)x - ((x < 0.0) ? 1 : 0));
Ivan Mahonin b53a5c
    return (int)x;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB int
Ivan Mahonin b53a5c
nk_ifloorf(float x)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    x = (float)((int)x - ((x < 0.0f) ? 1 : 0));
Ivan Mahonin b53a5c
    return (int)x;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB int
Ivan Mahonin b53a5c
nk_iceilf(float x)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    if (x >= 0) {
Ivan Mahonin b53a5c
        int i = (int)x;
Ivan Mahonin b53a5c
        return (x > i) ? i+1: i;
Ivan Mahonin b53a5c
    } else {
Ivan Mahonin b53a5c
        int t = (int)x;
Ivan Mahonin b53a5c
        float r = x - (float)t;
Ivan Mahonin b53a5c
        return (r > 0.0f) ? t+1: t;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB int
Ivan Mahonin b53a5c
nk_log10(double n)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    int neg;
Ivan Mahonin b53a5c
    int ret;
Ivan Mahonin b53a5c
    int exp = 0;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    neg = (n < 0) ? 1 : 0;
Ivan Mahonin b53a5c
    ret = (neg) ? (int)-n : (int)n;
Ivan Mahonin b53a5c
    while ((ret / 10) > 0) {
Ivan Mahonin b53a5c
        ret /= 10;
Ivan Mahonin b53a5c
        exp++;
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
    if (neg) exp = -exp;
Ivan Mahonin b53a5c
    return exp;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_rect
Ivan Mahonin b53a5c
nk_get_null_rect(void)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_null_rect;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_rect
Ivan Mahonin b53a5c
nk_rect(float x, float y, float w, float h)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_rect r;
Ivan Mahonin b53a5c
    r.x = x; r.y = y;
Ivan Mahonin b53a5c
    r.w = w; r.h = h;
Ivan Mahonin b53a5c
    return r;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_rect
Ivan Mahonin b53a5c
nk_recti(int x, int y, int w, int h)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_rect r;
Ivan Mahonin b53a5c
    r.x = (float)x;
Ivan Mahonin b53a5c
    r.y = (float)y;
Ivan Mahonin b53a5c
    r.w = (float)w;
Ivan Mahonin b53a5c
    r.h = (float)h;
Ivan Mahonin b53a5c
    return r;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_rect
Ivan Mahonin b53a5c
nk_recta(struct nk_vec2 pos, struct nk_vec2 size)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_rect(pos.x, pos.y, size.x, size.y);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_rect
Ivan Mahonin b53a5c
nk_rectv(const float *r)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_rect(r[0], r[1], r[2], r[3]);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_rect
Ivan Mahonin b53a5c
nk_rectiv(const int *r)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_recti(r[0], r[1], r[2], r[3]);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_vec2
Ivan Mahonin b53a5c
nk_rect_pos(struct nk_rect r)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_vec2 ret;
Ivan Mahonin b53a5c
    ret.x = r.x; ret.y = r.y;
Ivan Mahonin b53a5c
    return ret;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_vec2
Ivan Mahonin b53a5c
nk_rect_size(struct nk_rect r)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_vec2 ret;
Ivan Mahonin b53a5c
    ret.x = r.w; ret.y = r.h;
Ivan Mahonin b53a5c
    return ret;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB struct nk_rect
Ivan Mahonin b53a5c
nk_shrink_rect(struct nk_rect r, float amount)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_rect res;
Ivan Mahonin b53a5c
    r.w = NK_MAX(r.w, 2 * amount);
Ivan Mahonin b53a5c
    r.h = NK_MAX(r.h, 2 * amount);
Ivan Mahonin b53a5c
    res.x = r.x + amount;
Ivan Mahonin b53a5c
    res.y = r.y + amount;
Ivan Mahonin b53a5c
    res.w = r.w - 2 * amount;
Ivan Mahonin b53a5c
    res.h = r.h - 2 * amount;
Ivan Mahonin b53a5c
    return res;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB struct nk_rect
Ivan Mahonin b53a5c
nk_pad_rect(struct nk_rect r, struct nk_vec2 pad)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    r.w = NK_MAX(r.w, 2 * pad.x);
Ivan Mahonin b53a5c
    r.h = NK_MAX(r.h, 2 * pad.y);
Ivan Mahonin b53a5c
    r.x += pad.x; r.y += pad.y;
Ivan Mahonin b53a5c
    r.w -= 2 * pad.x;
Ivan Mahonin b53a5c
    r.h -= 2 * pad.y;
Ivan Mahonin b53a5c
    return r;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_vec2
Ivan Mahonin b53a5c
nk_vec2(float x, float y)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_vec2 ret;
Ivan Mahonin b53a5c
    ret.x = x; ret.y = y;
Ivan Mahonin b53a5c
    return ret;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_vec2
Ivan Mahonin b53a5c
nk_vec2i(int x, int y)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    struct nk_vec2 ret;
Ivan Mahonin b53a5c
    ret.x = (float)x;
Ivan Mahonin b53a5c
    ret.y = (float)y;
Ivan Mahonin b53a5c
    return ret;
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_vec2
Ivan Mahonin b53a5c
nk_vec2v(const float *v)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_vec2(v[0], v[1]);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_API struct nk_vec2
Ivan Mahonin b53a5c
nk_vec2iv(const int *v)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    return nk_vec2i(v[0], v[1]);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
NK_LIB void
Ivan Mahonin b53a5c
nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,
Ivan Mahonin b53a5c
    float x1, float y1)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    NK_ASSERT(a);
Ivan Mahonin b53a5c
    NK_ASSERT(clip);
Ivan Mahonin b53a5c
    clip->x = NK_MAX(a->x, x0);
Ivan Mahonin b53a5c
    clip->y = NK_MAX(a->y, y0);
Ivan Mahonin b53a5c
    clip->w = NK_MIN(a->x + a->w, x1) - clip->x;
Ivan Mahonin b53a5c
    clip->h = NK_MIN(a->y + a->h, y1) - clip->y;
Ivan Mahonin b53a5c
    clip->w = NK_MAX(0, clip->w);
Ivan Mahonin b53a5c
    clip->h = NK_MAX(0, clip->h);
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
NK_API void
Ivan Mahonin b53a5c
nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,
Ivan Mahonin b53a5c
    float pad_x, float pad_y, enum nk_heading direction)
Ivan Mahonin b53a5c
{
Ivan Mahonin b53a5c
    float w_half, h_half;
Ivan Mahonin b53a5c
    NK_ASSERT(result);
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    r.w = NK_MAX(2 * pad_x, r.w);
Ivan Mahonin b53a5c
    r.h = NK_MAX(2 * pad_y, r.h);
Ivan Mahonin b53a5c
    r.w = r.w - 2 * pad_x;
Ivan Mahonin b53a5c
    r.h = r.h - 2 * pad_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    r.x = r.x + pad_x;
Ivan Mahonin b53a5c
    r.y = r.y + pad_y;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    w_half = r.w / 2.0f;
Ivan Mahonin b53a5c
    h_half = r.h / 2.0f;
Ivan Mahonin b53a5c
Ivan Mahonin b53a5c
    if (direction == NK_UP) {
Ivan Mahonin b53a5c
        result[0] = nk_vec2(r.x + w_half, r.y);
Ivan Mahonin b53a5c
        result[1] = nk_vec2(r.x + r.w, r.y + r.h);
Ivan Mahonin b53a5c
        result[2] = nk_vec2(r.x, r.y + r.h);
Ivan Mahonin b53a5c
    } else if (direction == NK_RIGHT) {
Ivan Mahonin b53a5c
        result[0] = nk_vec2(r.x, r.y);
Ivan Mahonin b53a5c
        result[1] = nk_vec2(r.x + r.w, r.y + h_half);
Ivan Mahonin b53a5c
        result[2] = nk_vec2(r.x, r.y + r.h);
Ivan Mahonin b53a5c
    } else if (direction == NK_DOWN) {
Ivan Mahonin b53a5c
        result[0] = nk_vec2(r.x, r.y);
Ivan Mahonin b53a5c
        result[1] = nk_vec2(r.x + r.w, r.y);
Ivan Mahonin b53a5c
        result[2] = nk_vec2(r.x + w_half, r.y + r.h);
Ivan Mahonin b53a5c
    } else {
Ivan Mahonin b53a5c
        result[0] = nk_vec2(r.x, r.y + h_half);
Ivan Mahonin b53a5c
        result[1] = nk_vec2(r.x + r.w, r.y);
Ivan Mahonin b53a5c
        result[2] = nk_vec2(r.x + r.w, r.y + r.h);
Ivan Mahonin b53a5c
    }
Ivan Mahonin b53a5c
}
Ivan Mahonin b53a5c