<|start_filename|>src/hostmem.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2018 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


#include "internal.h"

#if defined(LINUX)
#define AlignedAlloc aligned_alloc
#define AlignedFree  free
#elif defined(MINGW)
#define AlignedAlloc _aligned_malloc
#define AlignedFree  _aligned_free
#else
#error "Cannot determine platform"
#endif

static int freehostmem(lua_State *L, ud_t *ud)
    {
    hostmem_t* hostmem = (hostmem_t*)ud->handle;
    int allocated = IsAllocated(ud);
    if(!freeuserdata(L, ud, "hostmem")) return 0;
    if(allocated)
        AlignedFree(hostmem->ptr);
    Free(L, hostmem);
    return 0;
    }

static ud_t *newhostmem(lua_State *L, hostmem_t* hostmem) 
    {
    ud_t *ud;
    ud = newuserdata(L, hostmem, HOSTMEM_MT, "hostmem");
    ud->destructor = freehostmem;  
    return ud;
    }

static int CreateAllocated(lua_State *L, char *ptr, size_t size)
    {
    ud_t *ud;
    hostmem_t* hostmem;
    hostmem = (hostmem_t*)MallocNoErr(L, sizeof(hostmem_t));
    if(!hostmem)
        {
        free(ptr);
        return luaL_error(L, errstring(ERR_MEMORY));
        }
    hostmem->ptr = ptr;
    hostmem->size = size;
    ud = newhostmem(L, hostmem);
    MarkAllocated(ud);
    return 1;
    }

static int CreatePack(lua_State *L, int arg, size_t alignment)
    {
    int err;
    char *ptr;
    int type = checktype(L, arg);
    size_t n = toflattable(L, arg+1);
    size_t size = n * sizeoftype(type);

    if(size == 0) 
        return luaL_argerror(L, arg+1, errstring(ERR_LENGTH));

    ptr = (char*)AlignedAlloc(alignment, size);
    if(!ptr)
        return luaL_error(L, "failed to allocate page aligned memory");

    err = testdata(L, type, n, ptr, size);
    if(err)
        {
        free(ptr);
        return luaL_argerror(L, arg+1, errstring(err));
        }

    CreateAllocated(L, ptr, size);
    return 1;
    }


static int Create(lua_State *L, int arg, size_t alignment)
    {
    const char *data = NULL;
    char *ptr;
    size_t size;

    if(lua_type(L, arg) == LUA_TSTRING)
        {
        if(!lua_isnoneornil(L, arg+1))
            return CreatePack(L, arg, alignment);
    
        data = luaL_checklstring(L, arg, &size);
        if(size == 0) 
            return luaL_argerror(L, arg, errstring(ERR_LENGTH));
        }
    else
        {
        size = luaL_checkinteger(L, arg);
        if(size == 0) 
            return luaL_argerror(L, arg, errstring(ERR_VALUE));
        }

    ptr = (char*)AlignedAlloc(alignment, size); // (char*)Malloc(L, size);
    if(!ptr)
        return luaL_error(L, "failed to allocate page aligned memory");
            
    if(data)
        memcpy(ptr, data, size);
    else
        memset(ptr, 0, size);

    CreateAllocated(L, ptr, size);
    return 1;
    }

static int CreateAlignedAlloc(lua_State *L)
    {
    size_t alignment = luaL_checkinteger(L, 1);
    return Create(L, 2, alignment);
    }

static int CreateMalloc(lua_State *L)
    {
    return Create(L, 1, 8);
    }


static int CreateHostmem(lua_State *L)
    {
    size_t size;
    const char *ptr;
    hostmem_t* hostmem;

    if(lua_type(L, 1) == LUA_TSTRING)
        {
        ptr = lua_tolstring(L, 1, &size);
        }
    else
        {
        size = luaL_checkinteger(L, 1);
        ptr = (char*)checklightuserdata(L, 2);
        }

    if(size == 0)
        return luaL_argerror(L, 1, errstring(ERR_LENGTH));

    hostmem = (hostmem_t*)MallocNoErr(L, sizeof(hostmem_t));
    if(!hostmem)
        {
        Free(L, hostmem);
        return luaL_error(L, errstring(ERR_MEMORY));
        }

    hostmem->ptr = (char*)ptr;
    hostmem->size = size;
    newhostmem(L, hostmem);
    return 1;
    }


static int WriteData(lua_State *L)
    {
    size_t size;
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_checkinteger(L, 2);
    /* arg 3 should be nil */
    const char *data = luaL_checklstring(L, 4, &size);
    if(size == 0)
        return 0;
    if((offset >= hostmem->size) || (size > hostmem->size - offset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    memcpy(hostmem->ptr + offset, data, size);
    return 0;
    }

static int CopyPtr(lua_State *L)
    {
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_checkinteger(L, 2);
    size_t size = luaL_checkinteger(L, 3);
    void *ptr = checklightuserdata(L, 4);
    if(size == 0)
        return 0;
    if((offset >= hostmem->size) || (size > hostmem->size - offset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    memcpy(hostmem->ptr + offset, ptr, size);
    return 0;
    }

static int CopyHostmem(lua_State *L)
    {
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_checkinteger(L, 2);
    size_t size = luaL_checkinteger(L, 3);
    hostmem_t* srchostmem = checkhostmem(L, 4, NULL);
    size_t srcoffset = luaL_checkinteger(L, 5);
    if(hostmem == srchostmem)
        return luaL_argerror(L, 4, "source and destination hostmem are the same");
    if(size == 0)
        return 0;
    if((offset >= hostmem->size) || (size > hostmem->size - offset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    if((srcoffset >= srchostmem->size) || (size > srchostmem->size - srcoffset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    memcpy(hostmem->ptr + offset, srchostmem->ptr + srcoffset, size);
    return 0;
    }


static int WritePack(lua_State *L) 
    {
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_checkinteger(L, 2);
    int type = checktype(L, 3);
    size_t size = hostmem->size - offset;
    if(offset >= hostmem->size)
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    checkdata(L, 4, type, hostmem->ptr + offset, size);
    return 0;
    }

static int Write(lua_State *L)
    {
    int t = lua_type(L, 3);
    if(t == LUA_TSTRING) return WritePack(L);
    if(t == LUA_TNIL) return WriteData(L);
    return luaL_argerror(L, 3, errstring(ERR_TYPE));    
    }

static int Copy(lua_State *L)
    {
    int t = lua_type(L, 4);
    if(t == LUA_TLIGHTUSERDATA) return CopyPtr(L);
    if(t == LUA_TUSERDATA) return CopyHostmem(L);
    return luaL_argerror(L, 4, errstring(ERR_TYPE));    
    }
        
static int Clear(lua_State *L)
/* clear(offset, size, c) 
 */
    {
    size_t len;
    const char *s;
    char c;
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_checkinteger(L, 2);
    size_t size = luaL_checkinteger(L, 3);

    if(lua_type(L, 4) == LUA_TSTRING)
        {
        s = luaL_checklstring(L, 4, &len);
        if(len != 1)
            return luaL_argerror(L, 4, "invalid length"); /* must be 1 */
        c = s[0];
        }
    else
        c = luaL_optinteger(L, 4, 0);
    
    if((offset >= hostmem->size) || (size > hostmem->size - offset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    if(size == 0)
        return 0;
    memset(hostmem->ptr + offset, c, size);
    return 0;
    }

static int Read(lua_State *L)
    {
    int type;
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_optinteger(L, 2, 0);
    size_t size = luaL_optinteger(L, 3, hostmem->size - offset);
    if((offset >= hostmem->size) || (size > hostmem->size - offset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    if(lua_type(L, 4) == LUA_TSTRING) /* unpack according to 'type' */
        {
        type = checktype(L, 4);
        if(size == 0)
            { lua_newtable(L); return 1; }
        return pushdata(L, type, hostmem->ptr + offset, size);
        }
    if(size == 0)
        lua_pushstring(L, ""); 
    else
        lua_pushlstring(L, hostmem->ptr + offset, size);
    return 1;
    }

static int Ptr(lua_State *L)
    {
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    size_t offset = luaL_optinteger(L, 2, 0);
    size_t size = luaL_optinteger(L, 3, 0);
    if((offset >= hostmem->size) || (size > hostmem->size - offset))
        return luaL_error(L, errstring(ERR_BOUNDARIES));
    lua_pushlightuserdata(L, hostmem->ptr + offset);
    return 1;
    }


static int Size(lua_State *L)
    {
    size_t offset;
    char *ptr;
    hostmem_t* hostmem = checkhostmem(L, 1, NULL);
    if(lua_isnoneornil(L, 2))
        lua_pushinteger(L, hostmem->size);
    else if(lua_isinteger(L, 2))
        {
        offset = luaL_checkinteger(L, 2);
        if(offset >= hostmem->size)
            lua_pushinteger(L, 0);
        else
            lua_pushinteger(L, hostmem->size - offset);
        }
    else
        {
        ptr = (char*)checklightuserdata(L, 2);
        if((ptr < hostmem->ptr) || (ptr > (hostmem->ptr + hostmem->size)))
            lua_pushinteger(L, 0);
        else
            lua_pushinteger(L, hostmem->ptr + hostmem->size - ptr);
        }
    return 1;
    }


RAW_FUNC(hostmem)
TYPE_FUNC(hostmem)
DELETE_FUNC(hostmem)

static const struct luaL_Reg Methods[] = 
    {
        { "raw", Raw },
        { "type", Type },
        { "free", Delete },
        { "write", Write },
        { "copy", Copy },
        { "clear", Clear },
        { "read", Read },
        { "ptr", Ptr },
        { "size", Size },
        { NULL, NULL } /* sentinel */
    };


static const struct luaL_Reg MetaMethods[] = 
    {
        { "__gc",  Delete },
        { NULL, NULL } /* sentinel */
    };


static const struct luaL_Reg Functions[] = 
    {
        { "malloc", CreateMalloc },
        { "aligned_alloc", CreateAlignedAlloc },
        { "hostmem", CreateHostmem },
        { "free",  Delete },
        { NULL, NULL } /* sentinel */
    };


void moonglmath_open_hostmem(lua_State *L)
    {
    udata_define(L, HOSTMEM_MT, Methods, MetaMethods);
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>src/vec.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Check and push                                                               |
 *------------------------------------------------------------------------------*/

int testvec(lua_State *L, int arg, vec_t v, size_t *size, unsigned int *isrow)
/* Tests if the element at arg is a vector and sets v, *size and *isrow accordingly
 * (unless they are passed as 0).
 */
    {
    size_t i;
    size_t size_;
    unsigned int isrow_;
    if(!testmetatable(L, arg, VEC_MT)) return 0;

    lua_getfield(L, arg, "type");   
    isrow_ = checkisrow(L, -1);
    lua_pop(L, 1);

    lua_getfield(L, arg, "size");
    size_ = luaL_checkinteger(L, -1);
    lua_pop(L, 1);
    checkvecsize(L, size_);

    if(isrow != NULL) *isrow = isrow_;
    if(size != NULL) *size = size_;
    if(v != NULL)
        {
        vec_clear(v);
        for(i=0; i < size_; i++)
            {
            lua_geti(L, arg, i+1);
            v[i] = luaL_checknumber(L, -1);
            lua_pop(L, 1);
            }
        }
    return 1;
    }

int checkvec(lua_State *L, int arg, vec_t v, size_t *size, unsigned int *isrow)
/* Same as testvec(), but raises a error if the test fails.
 */
    {
    if(!testvec(L, arg, v, size, isrow))
        return luaL_argerror(L, arg, lua_pushfstring(L, "%s expected", VEC_MT));
    return 1;
    }


int pushvec(lua_State *L, vec_t v, size_t vsize, size_t size, unsigned int isrow)
/* vsize = no. of valid elements in v
 * if vsize > size, the exceeding elements are discarded,
 * if vsize < size, the missing elements are set to 0.
 */
    {
    size_t i;
    checkvecsize(L, size);
    lua_newtable(L);
    setmetatable(L, VEC_MT);
    for(i=0; i<size; i++)
        {
        lua_pushnumber(L, i < vsize ? v[i] : 0);
        lua_seti(L, -2, i+1);
        }
    lua_pushinteger(L, size);
    lua_setfield(L, -2, "size");
    pushisrow(L, isrow);
    lua_setfield(L, -2, "type");
    return 1;
    }

/*------------------------------------------------------------------------------*
 | Vec                                                                          |
 *------------------------------------------------------------------------------*/

static int Vec(lua_State *L, size_t size, unsigned int isrow)
/* creates a vector of size 'size', from a vector or a list of values 
 * the size is adapted by discarding exceeding values or adding zeros
 * in lieu of missing values.
 * vecN(v)
 * vecN([x1 ,[x2,...[,xN]]])
 */
    {
    vec_t v;
    size_t vsize, i, arg;
    arg = 1;
    if(testvec(L, arg, v, &vsize, NULL))
        return pushvec(L, v, vsize, size, isrow);
    checkvecsize(L, size);
    for(i = 0; i < size; i++)
        v[i] = luaL_optnumber(L, arg++, 0);
    return pushvec(L, v, size, size, isrow);
    }

static int Vec2(lua_State *L) { return Vec(L, 2, 0); }
static int Vec3(lua_State *L) { return Vec(L, 3, 0); }
static int Vec4(lua_State *L) { return Vec(L, 4, 0); }
static int Vec2r(lua_State *L) { return Vec(L, 2, 1); }
static int Vec3r(lua_State *L) { return Vec(L, 3, 1); }
static int Vec4r(lua_State *L) { return Vec(L, 4, 1); }

static int IsVec(lua_State *L, size_t size, unsigned int isrow)
    {
    size_t vsize;
    unsigned int visrow;
    if(!testvec(L, 1, NULL, &vsize, &visrow))
        lua_pushboolean(L, 0);
    else
        lua_pushboolean(L, (vsize==size) && (visrow==isrow));
    return 1;
    }
    
static int IsVec2(lua_State *L) { return IsVec(L, 2, 0); }
static int IsVec3(lua_State *L) { return IsVec(L, 3, 0); }
static int IsVec4(lua_State *L) { return IsVec(L, 4, 0); }
static int IsVec2r(lua_State *L) { return IsVec(L, 2, 1); }
static int IsVec3r(lua_State *L) { return IsVec(L, 3, 1); }
static int IsVec4r(lua_State *L) { return IsVec(L, 4, 1); }

/*------------------------------------------------------------------------------*
 | ToString                                                                     |
 *------------------------------------------------------------------------------*/

#if 0
static int ToString(lua_State *L)
    {
    vec_t v;
    size_t size;
    unsigned int isrow;
    checkvec(L, 1, v, &size, &isrow);
    switch(size)
        {
#define T isrow==1 ? "" : "'"
        case 2: lua_pushfstring(L, "[%f %f]%s", v[0], v[1], T ); break;
        case 3: lua_pushfstring(L, "[%f %f %f]%s", v[0], v[1], v[2], T); break;
        case 4: lua_pushfstring(L, "[%f %f %f %f]%s", v[0], v[1], v[2], v[3], T); break;
        default:
            return luaL_error(L, UNEXPECTED_ERROR);
        }
    return 1;
    }
#endif

static int ToString_(lua_State *L, vec_t v, size_t size, unsigned int isrow)
/* With snprintf because lua_pushfstring does not support the %g conversion specifier */
    {
#define SZ 512
#define space (SZ-p)
    char str[SZ];
    int p=0;
    switch(size)
        {
#define T isrow==1 ? "" : "'"
        case 2: p = snprintf(str, space, "{ "FMT", "FMT" }%s", v[0], v[1], T ); break;
        case 3: p = snprintf(str, space, "{ "FMT", "FMT", "FMT" }%s", 
                                                v[0], v[1], v[2], T); break;
        case 4: p = snprintf(str, space, "{ "FMT", "FMT", "FMT", "FMT" }%s", 
                                                v[0], v[1], v[2], v[3], T); break;
        default:
            return luaL_error(L, UNEXPECTED_ERROR);
        }
    if(space<0)
        { 
        /* truncate */
        p = SZ - 5; 
        p+=snprintf(str+p, space, " ...");
        lua_pushlstring(L, str, p);
        return 1;
        }
    lua_pushlstring(L, str, p);
    return 1;
#undef space
#undef SZ
    }

static int ToString(lua_State *L)
    {
    vec_t v;
    size_t size;
    unsigned int isrow;
    checkvec(L, 1, v, &size, &isrow);
    return ToString_(L, v, size, isrow);
    }


static int Concat(lua_State *L)
    {
    vec_t v;
    size_t size;
    unsigned int isrow;
    if(testvec(L, 1, v, &size, &isrow))
        {
        ToString_(L, v, size, isrow);
        lua_pushvalue(L, 2);
        }
    else if(testvec(L, 2, v, &size, &isrow))
        {
        lua_pushvalue(L, 1);
        ToString_(L, v, size, isrow);
        }
    else 
        return unexpected(L);
    lua_concat(L, 2);
    return 1;
    }


/*------------------------------------------------------------------------------*
 | Non-Lua functions (for internal use)                                         |
 *------------------------------------------------------------------------------*/

void vec_unm(vec_t dst, vec_t v, size_t n)
    {
    size_t i;
    vec_clear(dst);
    for(i=0; i < n; i++)    
        dst[i] = -v[i];
    }
    
void vec_add(vec_t dst, vec_t v1, vec_t v2, size_t n)
    {
    size_t i;
    vec_clear(dst);
    for(i=0; i < n; i++)    
        dst[i] = v1[i] + v2[i];
    }
    
void vec_sub(vec_t dst, vec_t v1, vec_t v2, size_t n)
    {
    size_t i;
    vec_clear(dst);
    for(i=0; i < n; i++)    
        dst[i] = v1[i] - v2[i];
    }
    
double vec_norm(vec_t v, size_t n)
    {
    size_t i;
    double r = 0;
    for(i=0; i < n; i++)
        r += v[i]*v[i];
    return sqrt(r);
    }

double vec_norm2(vec_t v, size_t n)
    {
    size_t i;
    double r = 0;
    for(i=0; i < n; i++)
        r += v[i]*v[i];
    return r;
    }

void vec_normalize(vec_t v, size_t n) 
/* in place */
    {
    size_t i;
    double norm = vec_norm(v, n);
    for(i=0; i < n; i++)    
        v[i] = v[i]/norm;
    }
    
void vec_div(vec_t dst, vec_t v, double s, size_t n)
    {
    size_t i; 
    vec_clear(dst);
    for(i=0; i < n; i++)    
        dst[i] = v[i] / s;
    }

double vec_dot(vec_t v1, vec_t v2, size_t n)
/* dot product */
    {
    size_t i;
    double s = 0;
    for(i=0; i < n; i++)    
        s += (v1[i]*v2[i]);
    return s;
    }

void vec_vxs(vec_t dst, vec_t v, double s, size_t n)
    {
    size_t i; 
    for(i=0; i < n; i++)    
        dst[i] = v[i] * s;
    }

void vec_vxv(mat_t dst, vec_t v1, vec_t v2, size_t n)
/* v1 is a nx1 column vector
 * v2 is a 1xn row vector
 * m is a nxn square matrix (n x 1) * (1 x n) = (n x n)
 */
    {
    size_t i, j;
    for(i=0; i < n; i++)
        for(j=0; j < n; j++)
            dst[i][j] = v1[i] * v2[j];
    }

void vec_cross(vec_t dst, vec_t v1, vec_t v2)
/* dst is always to be regarded as a size=3 vector */
    {
    dst[0] = v1[1]*v2[2] - v1[2]*v2[1];
    dst[1] = v1[2]*v2[0] - v1[0]*v2[2];
    dst[2] = v1[0]*v2[1] - v1[1]*v2[0];
    dst[3] = 0;
    }

void vec_clamp(vec_t dst, vec_t v, vec_t minv, vec_t maxv, size_t n)
    {
    size_t i;
    for(i=0; i<n; i++)
        dst[i] = clamp(v[i], minv[i], maxv[i]);
    }

void vec_mix(vec_t dst, vec_t v1, vec_t v2, size_t n, double k)
    {
    size_t i;
    for(i=0; i<n; i++)
        dst[i] = mix(v1[i], v2[i], k);
    }

void vec_step(vec_t dst, vec_t v, vec_t edge, size_t n)
    {
    size_t i;
    for(i=0; i<n; i++)
        dst[i] = step(v[i], edge[i]);
    }

void vec_smoothstep(vec_t dst, vec_t v, vec_t edge0, vec_t edge1, size_t n)
    {
    size_t i;
    for(i=0; i<n; i++)
        dst[i] = smoothstep(v[i], edge0[i], edge1[i]);
    }

void vec_fade(vec_t dst, vec_t v, vec_t edge0, vec_t edge1, size_t n)
    {
    size_t i;
    for(i=0; i<n; i++)
        dst[i] = fade(v[i], edge0[i], edge1[i]);
    }


/*------------------------------------------------------------------------------*
 | Metamethods                                                                  |
 *------------------------------------------------------------------------------*/

static int Unm(lua_State *L)
    {
    vec_t v; 
    size_t size, i; 
    unsigned int isrow;
    checkvec(L, 1, v, &size, &isrow);
    for(i=0; i < 4; i++)    
        v[i] = -v[i];
    return pushvec(L, v, size, size, isrow);
    }


static int Add(lua_State *L)
    {
    vec_t v, v1; 
    size_t size, size1, i; 
    unsigned int isrow, isrow1;
    checkvec(L, 1, v, &size, &isrow);
    checkvec(L, 2, v1, &size1, &isrow1);
    if((isrow != isrow1) || (size != size1))
        return luaL_error(L, OPERANDS_ERROR);
    for(i=0; i < size; i++) 
        v[i] += v1[i];
    return pushvec(L, v, size, size, isrow);
    }

static int Sub(lua_State *L)
    {
    vec_t v, v1; 
    size_t size, size1, i; 
    unsigned int isrow, isrow1;
    checkvec(L, 1, v, &size, &isrow);
    checkvec(L, 2, v1, &size1, &isrow1);
    if((isrow != isrow1) || (size != size1))
        return luaL_error(L, OPERANDS_ERROR);
    for(i=0; i < size; i++) 
        v[i] -= v1[i];
    return pushvec(L, v, size, size, isrow);
    }

static int Vxs(lua_State *L, int sarg, int varg)
    {
    vec_t v; 
    size_t size, i; 
    unsigned int isrow;
    double s = luaL_checknumber(L, sarg);
    checkvec(L, varg, v, &size, &isrow);
    for(i=0; i < size; i++) 
        v[i] *= s;
    return pushvec(L, v, size, size, isrow);
    }

static int Vxv(lua_State *L, vec_t v1, size_t nr,  vec_t v2, size_t nc) 
/* Nx1 * 1xM = NxM   (column) x (row) = matrix */
    {
    mat_t m;
    size_t i, j;
    for(i=0; i < nr; i++)
        for(j=0; j < nc; j++)
            m[i][j] = v1[i] * v2[j];
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Vxm(lua_State *L) /* 1xM * M*N = 1*N (row vector)*/
    {
    unsigned int isrow;
    size_t i, j, nr, nc, size;
    mat_t m;
    vec_t v, v1;
    double s;
    checkvec(L, 1, v, &size, &isrow);
    checkmat(L, 2, m, &nr, &nc);
    if( (!isrow) || (size != nr))
        return luaL_error(L, OPERANDS_ERROR);
    for(i=0; i < nc; i++)
        {
        s = 0;
        for(j=0; j < size; j++)
            s += (v[j] * m[j][i]);
        v1[i] = s;
        }
    return pushvec(L, v1, nc, nc, 1);
    }

static int Mul(lua_State *L)
    {
    vec_t v, v1; 
    size_t size, size1, i; 
    unsigned int isrow, isrow1;
    double r = 0;
    if(lua_isnumber(L, 1))
        return Vxs(L, 1, 2);
    if(lua_isnumber(L, 2))
        return Vxs(L, 2, 1);
    if(testmat(L, 2, NULL, NULL, NULL))
        return Vxm(L);
    checkvec(L, 1, v, &size, &isrow);
    checkvec(L, 2, v1, &size1, &isrow1);
    if((!isrow) && isrow1) /* Nx1 * 1xM = NxM */
        return Vxv(L, v, size, v1, size1);
    if(size != size1)
        return luaL_error(L, OPERANDS_ERROR);
    /* dot product:  1*N * Nx1, but also Nx1 * Nx1 and 1xN * 1*N are admitted */
    for(i=0; i < size; i++) 
        r += (v[i]*v1[i]);
    lua_pushnumber(L, r);
    return 1;
    }

static int Div(lua_State *L)
    {
    vec_t v; 
    size_t size, i; 
    unsigned int isrow;
    double s;
    checkvec(L, 1, v, &size, &isrow);
    s = luaL_checknumber(L, 2);
    for(i=0; i < size; i++) 
        v[i] /= s;
    return pushvec(L, v, size, size, isrow);
    }

static int Cross(lua_State *L)
/* always return a size=3 vector */
//@@ TODO?: v % scalar = component-wise mod
    {
    vec_t v1, v2, v;
    size_t size1, size2; 
    unsigned int isrow1, isrow2;
    checkvec(L, 1, v1, &size1, &isrow1);
    checkvec(L, 2, v2, &size2, &isrow2);
    if((isrow1 != isrow2) || (size1 != size2))
        return luaL_error(L, OPERANDS_ERROR);
    if(size1==2)
        v1[2] = v2[2] = 0;
    vec_cross(v, v1, v2);
    return pushvec(L, v, 3, 3, isrow1);
    }

int vec_Norm(lua_State *L)
    {
    vec_t v;
    size_t size, i;
    double r = 0;
    checkvec(L, 1, v, &size, NULL);
    for(i=0; i < size; i++) 
        r += v[i]*v[i];
    lua_pushnumber(L, sqrt(r));
    return 1;
    }

int vec_Norm2(lua_State *L)
    {
    vec_t v;
    size_t size, i;
    double r = 0;
    checkvec(L, 1, v, &size, NULL);
    for(i=0; i < size; i++)
        r += v[i]*v[i];
    lua_pushnumber(L, r);
    return 1;
    }

int vec_Normalize(lua_State *L)
    {
    vec_t v; 
    size_t size; 
    unsigned int isrow;
    checkvec(L, 1, v, &size, &isrow);
    vec_normalize(v, size);
    return pushvec(L, v, size, size, isrow);
    }


int vec_Transpose(lua_State *L)
    {
    vec_t v; size_t size; unsigned int isrow;
    checkvec(L, 1, v, &size, &isrow);
    return pushvec(L, v, size, size, !isrow);
    }

int vec_Clamp(lua_State *L)
    {
    vec_t dst, v, minv, maxv;
    size_t size, size1;
    unsigned int isrow, isrow1;
    checkvec(L, 1, v, &size, &isrow);
    checkvec(L, 2, minv, &size1, &isrow1);
    if(size1 != size || isrow1 != isrow)
        return luaL_error(L, OPERANDS_ERROR);
    checkvec(L, 3, maxv, &size1, &isrow1);
    if(size1 != size || isrow1 != isrow)
        return luaL_error(L, OPERANDS_ERROR);
    vec_clamp(dst, v, minv, maxv, size);
    return pushvec(L, dst, size, size, isrow);
    }

int vec_Mix(lua_State *L)
    {
    vec_t dst, v1, v2;
    double k;
    size_t size, size1;
    unsigned int isrow, isrow1;
    checkvec(L, 1, v1, &size, &isrow);
    checkvec(L, 2, v2, &size1, &isrow1);
    if(size1 != size || isrow1 != isrow)
        return luaL_error(L, OPERANDS_ERROR);
    k = luaL_checknumber(L, 3);
    vec_mix(dst, v1, v2, size, k);
    return pushvec(L, dst, size, size, isrow);
    }

int vec_Step(lua_State *L)
    {
    vec_t dst, v1, edge;
    double k;
    size_t size, size1;
    unsigned int isrow, isrow1;
    checkvec(L, 1, v1, &size, &isrow);
    if(lua_isnumber(L, 2))
        {
        k = lua_tonumber(L, 2);
        edge[0]=edge[1]=edge[2]=edge[3]=k;
        }
    else
        {
        checkvec(L, 2, edge, &size1, &isrow1);
        if(size1 != size || isrow1 != isrow)
            return luaL_error(L, OPERANDS_ERROR);
        }
    vec_step(dst, v1, edge, size);
    return pushvec(L, dst, size, size, isrow);
    }


int vec_Smoothstep(lua_State *L)
    {
    vec_t dst, v, edge0, edge1;
    double k;
    size_t size, size1;
    unsigned int isrow, isrow1;
    checkvec(L, 1, v, &size, &isrow);
    if(lua_isnumber(L, 2))
        {
        k = lua_tonumber(L, 2);
        edge0[0]=edge0[1]=edge0[2]=edge0[3]=k;
        }
    else
        {
        checkvec(L, 2, edge0, &size1, &isrow1);
        if(size1 != size || isrow1 != isrow)
            return luaL_error(L, OPERANDS_ERROR);
        }
    if(lua_isnumber(L, 3))
        {
        k = lua_tonumber(L, 3);
        edge1[0]=edge1[1]=edge1[2]=edge1[3]=k;
        }
    else
        {
        checkvec(L, 3, edge1, &size1, &isrow1);
        if(size1 != size || isrow1 != isrow)
            return luaL_error(L, OPERANDS_ERROR);
        }
    vec_smoothstep(dst, v, edge0, edge1, size);
    return pushvec(L, dst, size, size, isrow);
    }

int vec_Fade(lua_State *L)
    {
    vec_t dst, v, edge0, edge1;
    double k;
    size_t size, size1;
    unsigned int isrow, isrow1;
    checkvec(L, 1, v, &size, &isrow);
    if(lua_isnumber(L, 2))
        {
        k = lua_tonumber(L, 2);
        edge0[0]=edge0[1]=edge0[2]=edge0[3]=k;
        }
    else
        {
        checkvec(L, 2, edge0, &size1, &isrow1);
        if(size1 != size || isrow1 != isrow)
            return luaL_error(L, OPERANDS_ERROR);
        }
    if(lua_isnumber(L, 3))
        {
        k = lua_tonumber(L, 3);
        edge1[0]=edge1[1]=edge1[2]=edge1[3]=k;
        }
    else
        {
        checkvec(L, 3, edge1, &size1, &isrow1);
        if(size1 != size || isrow1 != isrow)
            return luaL_error(L, OPERANDS_ERROR);
        }
    vec_fade(dst, v, edge0, edge1, size);
    return pushvec(L, dst, size, size, isrow);
    }



static const struct luaL_Reg Metamethods[] = 
    {
        { "__tostring", ToString },
        { "__concat", Concat },
        { "__unm", Unm },
        { "__add", Add },
        { "__sub", Sub },
        { "__mul", Mul },
        { "__div", Div },
        { "__mod", Cross },
        { NULL, NULL } /* sentinel */
    };

static const struct luaL_Reg Methods[] = 
    {
        { "norm", vec_Norm },
        { "norm2", vec_Norm2 },
        { "normalize", vec_Normalize },
        { "transpose", vec_Transpose },
        { "clamp", vec_Clamp },
        { "mix", vec_Mix },
        { "step", vec_Step },
        { "smoothstep", vec_Smoothstep },
        { "fade", vec_Fade },
        { NULL, NULL } /* sentinel */
    };


/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "vec2", Vec2 },
        { "vec3", Vec3 },
        { "vec4", Vec4 },
        { "vec2r", Vec2r },
        { "vec3r", Vec3r },
        { "vec4r", Vec4r },
        { "isvec2", IsVec2 },
        { "isvec3", IsVec3 },
        { "isvec4", IsVec4 },
        { "isvec2r", IsVec2r },
        { "isvec3r", IsVec3r },
        { "isvec4r", IsVec4r },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_vec(lua_State *L)
    {
    newmetatable(L, VEC_MT);
    metatable_setfuncs(L, VEC_MT, Metamethods, Methods);
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>src/main.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

static lua_State *moonglmath_L = NULL;

static void AtExit(void)
    {
    if(moonglmath_L)
        {
        enums_free_all(moonglmath_L);
        moonglmath_L = NULL;
        }
    }

static int AddVersions(lua_State *L)
/* Add version strings to the gl table */
    {
    lua_pushstring(L, "_VERSION");
    lua_pushstring(L, "MoonGLMATH "MOONGLMATH_VERSION);
    lua_settable(L, -3);
    return 0;
    }

int luaopen_moonglmath(lua_State *L)
/* Lua calls this function to load the module */
    {
    moonglmath_L = L;
    moonglmath_utils_init(L);
    atexit(AtExit);

    lua_newtable(L); /* the gl table */
    AddVersions(L);

    /* add glmath functions: */
    moonglmath_open_enums(L);
    moonglmath_open_datahandling(L);
    moonglmath_open_tracing(L);
    moonglmath_open_vec(L);
    moonglmath_open_box(L);
    moonglmath_open_mat(L);
    moonglmath_open_quat(L);
    moonglmath_open_complex(L);
    moonglmath_open_funcs(L);
    moonglmath_open_transform(L);
    moonglmath_open_viewing(L);
    moonglmath_open_hostmem(L);

    /* Add functions implemented in Lua */
    lua_pushvalue(L, -1); lua_setglobal(L, "moonglmath");
    if(luaL_dostring(L, "require('moonglmath.vecsugar')") != 0) lua_error(L);
    if(luaL_dostring(L, "require('moonglmath.boxsugar')") != 0) lua_error(L);
    if(luaL_dostring(L, "require('moonglmath.matsugar')") != 0) lua_error(L);
    if(luaL_dostring(L, "require('moonglmath.quatsugar')") != 0) lua_error(L);
    if(luaL_dostring(L, "require('moonglmath.complexsugar')") != 0) lua_error(L);
    if(luaL_dostring(L, "require('moonglmath.utils')") != 0) lua_error(L);
    lua_pushnil(L);  lua_setglobal(L, "moonglmath");

    return 1;
    }



<|start_filename|>src/internal.h<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/********************************************************************************
 * Internal common header                                                       *
 ********************************************************************************/

#ifndef internalDEFINED
#define internalDEFINED

#ifdef LINUX
#define _ISOC11_SOURCE /* see man aligned_alloc(3) */
#endif
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include "moonglmath_local.h"

#define TOSTR_(x) #x
#define TOSTR(x) TOSTR_(x)

/* Note: all the dynamic symbols of this library (should) start with 'moonglmath_' .
 * The only exception is the luaopen_moonglmath() function, which is searched for
 * with that name by Lua.
 * MoonGLMATH's string references on the Lua registry also start with 'moonglmath_'.
 */

#include "tree.h"
#include "objects.h"
#include "enums.h"

/* A VECTOR is implemented as a table, with the elements in the array part:
 * v[i] = i-th element, i=1..N
 * vec.size = N (no. of elements)
 * vec.type = 'row' (1xN) or 'column' (Nx1)
 *
 * eg: v = { 10, 20, 30, size=3, type='column' }
 *
 * A MATRIX is implemented as a table of tables, where the tables in the
 * array part are the rows (i.e., row-major).
 * mat[i][j] = (i,j)-th element, i=1..N, j=1..M
 * mat.rows = N (no. of rows)
 * mat.columns = M (no. of columns)
 *
 * e.g. m = { { 11, 12, 13 }, { 14, 15, 16 }, rows=2, columns=3 }
 *
 * A QUATERNION is implemented as a table, with the elements in the array part:
 * w, x, y, z = q[1], q[2], q[3], q[4]
 *
 * A BOX is implemented as a table, with the elements in the array part
 * box = { minx, maxx, miny, maxy } (2D)
 * box = { minx, maxx, miny, maxy, minz, maxz } (3D)
 * box.dimensions = 2 or 3 (2D or 3D)
 */

#define FMT "%g"    // format used in __tostring()
//#define FMT "%.5f"

/*--------------------------------------------------------------------------*
 | Redefinitions                                                            |
 *--------------------------------------------------------------------------*/

#if 0
/* .c */
#define  moonglmath_
#endif

/* utils.c */
#define Malloc moonglmath_Malloc
void *Malloc(lua_State *L, size_t size);
#define MallocNoErr moonglmath_MallocNoErr
void *MallocNoErr(lua_State *L, size_t size);
#define Strdup moonglmath_Strdup
char *Strdup(lua_State *L, const char *s);
#define Free moonglmath_Free
void Free(lua_State *L, void *ptr);
#define now moonglmath_now
double now(void);
#define sleeep moonglmath_sleeep
void sleeep(double seconds);
#define since(t) (now() - (t))
#define checkoption_hint moonglmath_checkoption_hint
int checkoption_hint(lua_State *L, int arg, const char *def, const char *const lst[]);
#define isoption moonglmath_isoption
int isoption(lua_State *L, int arg, const char *const lst[]);
#define checkboolean moonglmath_checkboolean
int checkboolean(lua_State *L, int arg);
#define noprintf moonglmath_noprintf
int noprintf(const char *fmt, ...); 
#define notavailable moonglmath_notavailable
int notavailable(lua_State *L, ...);
#define newmetatable moonglmath_newmetatable
int newmetatable(lua_State *L, const char *metatable);
#define setmetatable moonglmath_setmetatable
int setmetatable(lua_State *L, const char *metatable);
#define metatable_setfuncs moonglmath_metatable_setfuncs
int metatable_setfuncs(lua_State *L, const char *metatable, const luaL_Reg *metamethods, 
            const luaL_Reg *methods);
#define checklightuserdata moonglmath_checklightuserdata
void *checklightuserdata(lua_State *L, int arg);
#define checklightuserdataorzero moonglmath_checklightuserdataorzero
void *checklightuserdataorzero(lua_State *L, int arg);
#define optlightuserdata moonglmath_optlightuserdata
void *optlightuserdata(lua_State *L, int arg);


#define checkvecsize(L, sz) do {                        \
    if(((sz)<1) || ((sz)>4))                            \
        return luaL_error(L, "invalid vector size");    \
} while(0)

#define checkboxdim(L, dim) do {                        \
    if(((dim)<2 || ((dim)>3)))                          \
        return luaL_error(L, "invalid box dimensions"); \
} while(0)

#define checkmatsize(L, nr, nc) do {                    \
    if(((nr)<1) || ((nr)>4) || ((nc)<1) || ((nc)>4))    \
        return luaL_error(L, "invalid matrix size");    \
} while(0)

/* vec.c ------------------------------------------------------------------------*/

#define vec_Norm moonglmath_vec_Norm
int vec_Norm(lua_State *L);
#define vec_Norm2 moonglmath_vec_Norm2
int vec_Norm2(lua_State *L);
#define vec_Normalize moonglmath_vec_Normalize
int vec_Normalize(lua_State *L);
#define vec_Transpose moonglmath_vec_Transpose
int vec_Transpose(lua_State *L);
#define vec_Clamp moonglmath_vec_Clamp
int vec_Clamp(lua_State *L);
#define vec_Mix moonglmath_vec_Mix
int vec_Mix(lua_State *L);
#define vec_Step moonglmath_vec_Step
int vec_Step(lua_State *L);
#define vec_Smoothstep moonglmath_vec_Smoothstep
int vec_Smoothstep(lua_State *L);
#define vec_Fade moonglmath_vec_Fade
int vec_Fade(lua_State *L);

/* box.c ------------------------------------------------------------------------*/

//@@TBD

/* mat.c ------------------------------------------------------------------------*/

#define mat_Transpose moonglmath_mat_Transpose
int mat_Transpose(lua_State *L);
#define mat_Trace moonglmath_mat_Trace
int mat_Trace(lua_State *L);
#define mat_Det moonglmath_mat_Det
int mat_Det(lua_State *L);
#define mat_Inv moonglmath_mat_Inv
int mat_Inv(lua_State *L);
#define mat_Adj moonglmath_mat_Adj
int mat_Adj(lua_State *L);
#define mat_Column moonglmath_mat_Column
int mat_Column(lua_State *L);
#define mat_Row moonglmath_mat_Row
int mat_Row(lua_State *L);
#define mat_Clamp moonglmath_mat_Clamp
int mat_Clamp(lua_State *L);
#define mat_Mix moonglmath_mat_Mix
int mat_Mix(lua_State *L);
#define mat_Step moonglmath_mat_Step
int mat_Step(lua_State *L);
#define mat_Smoothstep moonglmath_mat_Smoothstep
int mat_Smoothstep(lua_State *L);
#define mat_Fade moonglmath_mat_Fade
int mat_Fade(lua_State *L);

/* quat.c ------------------------------------------------------------------------*/
#define quat_Norm moonglmath_quat_Norm
int quat_Norm(lua_State *L);
#define quat_Norm2 moonglmath_quat_Norm2
int quat_Norm2(lua_State *L);
#define quat_Normalize moonglmath_quat_Normalize
int quat_Normalize(lua_State *L);
#define quat_Inv moonglmath_quat_Inv
int quat_Inv(lua_State *L);
#define quat_Parts moonglmath_quat_Parts
int quat_Parts(lua_State *L);
#define quat_Conj moonglmath_quat_Conj
int quat_Conj(lua_State *L);
#define quat_FromMat moonglmath_quat_FromMat
int quat_FromMat(lua_State *L);
#define quat_Mix moonglmath_quat_Mix
int quat_Mix(lua_State *L);
#define quat_Slerp moonglmath_quat_Slerp
int quat_Slerp(lua_State *L);

/* complex.c ------------------------------------------------------------------------*/
#define complex_Norm moonglmath_complex_Norm
int complex_Norm(lua_State *L);
#define complex_Norm2 moonglmath_complex_Norm2
int complex_Norm2(lua_State *L);
#define complex_Normalize moonglmath_complex_Normalize
int complex_Normalize(lua_State *L);
#define complex_Inv moonglmath_complex_Inv
int complex_Inv(lua_State *L);
#define complex_Parts moonglmath_complex_Parts
int complex_Parts(lua_State *L);
#define complex_Conj moonglmath_complex_Conj
int complex_Conj(lua_State *L);

/* num.c -------------------------------------------------------------------------*/

#define num_Clamp moonglmath_num_Clamp
int num_Clamp(lua_State *L);
#define num_Mix moonglmath_num_Mix
int num_Mix(lua_State *L);
#define num_Step moonglmath_num_Step
int num_Step(lua_State *L);
#define num_Smoothstep moonglmath_num_Smoothstep
int num_Smoothstep(lua_State *L);
#define num_Fade moonglmath_num_Fade
int num_Fade(lua_State *L);

/* datahandling.c */
#define sizeoftype moonglmath_sizeoftype
size_t sizeoftype(int type);
#define toflattable moonglmath_toflattable
int toflattable(lua_State *L, int arg);
#define testdata moonglmath_testdata
int testdata(lua_State *L, int type, size_t n, void *dst, size_t dstsize);
#define checkdata moonglmath_checkdata
int checkdata(lua_State *L, int arg, int type, void *dts, size_t dstsize);
#define pushdata moonglmath_pushdata
int pushdata(lua_State *L, int type, void *src, size_t srcsize);


/* main.c */
int luaopen_moonglmath(lua_State *L);
void moonglmath_utils_init(lua_State *L);
void moonglmath_open_datahandling(lua_State *L);
void moonglmath_open_tracing(lua_State *L);
void moonglmath_open_enums(lua_State *L);
void moonglmath_open_mat(lua_State *L);
void moonglmath_open_vec(lua_State *L);
void moonglmath_open_box(lua_State *L);
void moonglmath_open_quat(lua_State *L);
void moonglmath_open_complex(lua_State *L);
void moonglmath_open_transform(lua_State *L);
void moonglmath_open_viewing(lua_State *L);
void moonglmath_open_funcs(lua_State *L);

/*------------------------------------------------------------------------------*
 | Debug and other utilities                                                    |
 *------------------------------------------------------------------------------*/

/* Internal error codes */
#define ERR_NOTPRESENT       1
#define ERR_SUCCESS          0
#define ERR_GENERIC         -1
#define ERR_TYPE            -2
#define ERR_VALUE           -3
#define ERR_TABLE           -4
#define ERR_EMPTY           -5
#define ERR_MEMORY          -6
#define ERR_MALLOC_ZERO     -7
#define ERR_LENGTH          -8
#define ERR_POOL            -9
#define ERR_BOUNDARIES      -10
#define ERR_UNKNOWN         -11
#define errstring moonglmath_errstring
const char* errstring(int err);

/* tracing.c */
#define trace_objects moonglmath_trace_objects
extern int trace_objects;

#define badvalue(L,s)   lua_pushfstring((L), "invalid value '%s'", (s))

//#define checkoption checkoption_hint
#define checkoption luaL_checkoption

#define UNUSED noprintf /* to avoid warnings for unused parameters */

/* If this is printed, it denotes a suspect bug: */
#define UNEXPECTED_ERROR "unexpected error (%s, %d)", __FILE__, __LINE__
#define unexpected(L) luaL_error((L), UNEXPECTED_ERROR)

#define NARGS_ERROR "wrong number of arguments"
#define PERM_ERROR "operation not permitted"
/*#define OPERANDS_ERROR "invalid operands"*/
#define OPERANDS_ERROR "invalid operands (%s, %d)", __FILE__, __LINE__

#define NOT_AVAILABLE do { return luaL_error(L, "function not available"); } while(0)

#define NOT_IMPLEMENTED(func)               \
static int func(lua_State *L)               \
    { return luaL_error(L, "function "#func" is not implemented");  }

#define NOT_SUPPORTED(func)                 \
static int func(lua_State *L)               \
    { return luaL_error(L, "function "#func" is not supported"); return 0;  }


/*-----------------------------------------------------------------------*/
#if defined(DEBUG)

#define TSTART double ts = now();
#define TSTOP do {                                          \
    ts = since(ts); ts = ts*1e6;                            \
    printf("%s %d %.3f us\n", __FILE__, __LINE__, ts);      \
    ts = now();                                             \
} while(0);

#define DBG printf

#define TR() do {                                           \
    printf("trace %s %d\n",__FILE__,__LINE__);              \
} while(0)

#define BK() do {                                           \
    printf("break %s %d\n",__FILE__,__LINE__);              \
    getchar();                                              \
} while(0)

/*-----------------------------------------------------------------------*/
#else 

#define TSTART do {} while(0) 
#define TSTOP do {} while(0)    
#define DBG noprintf
#define TR()
#define BK()

/*-----------------------------------------------------------------------*/
#endif /* DEBUG */


#if 0 /* 7yy */
        { "",  },
static int (lua_State *L) //@@
    {
    CheckError(L);
    return 0;
    }

#endif

#endif /* internalDEFINED */


<|start_filename|>src/complex.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2018 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Check and push                                                               |
 *------------------------------------------------------------------------------*/

int testcomplex(lua_State *L, int arg, complex_t *z)
/* Tests if the element at arg is a complex number and sets z accordingly
 * (unless it is passed as 0).
 * Accepts also a real number x, in which case z = x+I*0;
 */
    {
    double x, y;
    if(lua_isnumber(L, arg))
        {
        if(z != NULL)
            *z = lua_tonumber(L, arg);
        return 1;
        }

    if(!testmetatable(L, arg, COMPLEX_MT)) return 0;

    if(z != NULL)
        {
        lua_geti(L, arg, 1);
        x = luaL_checknumber(L, -1);
        lua_pop(L, 1);
        lua_geti(L, arg, 2);
        y = luaL_checknumber(L, -1);
        lua_pop(L, 1);
        *z = x + I*y;
        }
    return 1;
    }

int checkcomplex(lua_State *L, int arg, complex_t *z)
/* Same as testcomplex(), but raises an error if the test fails.
 */
    {
    if(!testcomplex(L, arg, z))
        return luaL_argerror(L, arg, lua_pushfstring(L, "%s expected", COMPLEX_MT));
    return 1;
    }


int pushcomplex(lua_State *L, complex_t z)
    {
    lua_newtable(L);
    setmetatable(L, COMPLEX_MT);
    lua_pushnumber(L, creal(z));
    lua_seti(L, -2, 1);
    lua_pushnumber(L, cimag(z));
    lua_seti(L, -2, 2);
    return 1;
    }

/*------------------------------------------------------------------------------*
 |                                                                              |
 *------------------------------------------------------------------------------*/

static int ComplexArray(lua_State *L)
    {
    double x, y;
    int i, j, tbl;
    int n = luaL_len(L, 1);
    lua_newtable(L);
    tbl = lua_gettop(L);
    j = 0;
    for(i=0; i < n; )
        {
        lua_rawgeti(L, 1, ++i);
        x = luaL_optnumber(L, -1, 0);
        lua_rawgeti(L, 1, ++i);
        y = luaL_optnumber(L, -1, 0);
        lua_pop(L, 2);
        pushcomplex(L, x + I*y);
        lua_rawseti(L, tbl, ++j);
        }
    return 1;
    }

static int Complex(lua_State *L)
/* creates a complex number from another on or from its real and imag parts
 * complex()      --> 0+0i
 * complex(x, y)  --> x+yi
 * complex(z)     --> z
 * complex({x1, y1, x2, y2, ...}) --> {z1, z2, ...}
 */
    {
    complex_t z;
    double x, y;
    int t = lua_type(L, 1);

    if((t == LUA_TNONE)||(t == LUA_TNIL)||(t == LUA_TNUMBER))
        {
        x = luaL_optnumber(L, 1, 0);
        y = luaL_optnumber(L, 2, 0);
        z = x + I*y;
        }
    else if(t == LUA_TTABLE && !testmetatable(L, 1, COMPLEX_MT))
        return ComplexArray(L);
    else
        checkcomplex(L, 1, &z);
    return pushcomplex(L, z);
    }
    
static int IsComplex(lua_State *L)
    {
    if(!testcomplex(L, 1, NULL))
        lua_pushboolean(L, 0);
    else
        lua_pushboolean(L, 1);
    return 1;
    }
    
/*------------------------------------------------------------------------------*
 | ToString                                                                     |
 *------------------------------------------------------------------------------*/

static int ToString_(lua_State *L, complex_t z)
/* With snprintf because lua_pushfstring does not support the %g conversion specifier */
    {
#define SZ 512
#define space (SZ-p)
    char str[SZ];
    int p=0;
    if(cimag(z)>=0)
        p = snprintf(str, space, ""FMT"+"FMT"i", creal(z), cimag(z));
    else
        p = snprintf(str, space, ""FMT""FMT"i", creal(z), cimag(z));
    lua_pushlstring(L, str, p);
    return 1;
#undef space
#undef SZ
    }

static int ToString(lua_State *L)
    {
    complex_t z;
    checkcomplex(L, 1, &z);
    return ToString_(L, z);
    }


static int Concat(lua_State *L)
    {
    complex_t z;
    if(testcomplex(L, 1, &z))
        {
        ToString_(L, z);
        lua_pushvalue(L, 2);
        }
    else if(testcomplex(L, 2, &z))
        {
        lua_pushvalue(L, 1);
        ToString_(L, z);
        }
    else 
        return unexpected(L);
    lua_concat(L, 2);
    return 1;
    }

/*------------------------------------------------------------------------------*
 | C99 complex.h functions                                                      |
 *------------------------------------------------------------------------------*/

#define FUNC(Func, what)                \
static int Func(lua_State *L)           \
    {                                   \
    complex_t z;                        \
    checkcomplex(L, 1, &z);             \
    lua_pushnumber(L, what(z));         \
    return 1;                           \
    }

FUNC(Carg, carg)
FUNC(Cimag, cimag)
FUNC(Creal, creal)

#undef FUNC

#define FUNC(Func, what)                \
static int Func(lua_State *L)           \
    {                                   \
    complex_t z;                        \
    checkcomplex(L, 1, &z);             \
    return pushcomplex(L, what(z));     \
    }

FUNC(Csin, csin)
FUNC(Ccos, ccos)
FUNC(Ctan, ctan)
FUNC(Casin, casin)
FUNC(Cacos, cacos)
FUNC(Catan, catan)
FUNC(Csinh, csinh)
FUNC(Ccosh, ccosh)
FUNC(Ctanh, ctanh)
FUNC(Casinh, casinh)
FUNC(Cacosh, cacosh)
FUNC(Catanh, catanh)
FUNC(Cproj, cproj)
FUNC(Clog, clog)
FUNC(Cexp, cexp)
FUNC(Csqrt, csqrt)

#undef FUNC

/*------------------------------------------------------------------------------*
 | Metamethods                                                                  |
 *------------------------------------------------------------------------------*/

static int Unm(lua_State *L)
    {
    complex_t z; 
    checkcomplex(L, 1, &z);
    return pushcomplex(L, -z);
    }

#define FUNC(Func, what)                \
static int Func(lua_State *L)           \
    {                                   \
    complex_t z, z1;                    \
    checkcomplex(L, 1, &z);             \
    checkcomplex(L, 2, &z1);            \
    return pushcomplex(L, z what z1);   \
    }

FUNC(Add, +)
FUNC(Sub, -)
FUNC(Mul, *)
FUNC(Div, /)

#undef FUNC

static int Pow(lua_State *L)
    {
    complex_t z, z1;
    checkcomplex(L, 1, &z);
    checkcomplex(L, 2, &z1);
    return pushcomplex(L, cpow(z, z1));
    }


int complex_Norm(lua_State *L)
    {
    complex_t z;
    checkcomplex(L, 1, &z);
    lua_pushnumber(L, cabs(z));
    return 1;
    }

int complex_Norm2(lua_State *L)
    {
    complex_t z;
    double r; 
    checkcomplex(L, 1, &z);
    r = cabs(z);
    lua_pushnumber(L, r*r);
    return 1;
    }

int complex_Normalize(lua_State *L)
    {
    complex_t z; 
    checkcomplex(L, 1, &z);
    return pushcomplex(L, z/cabs(z));
    }

int complex_Inv(lua_State *L)
    {
    complex_t z;
    checkcomplex(L, 1, &z);
    return pushcomplex(L, 1/z);
    }

int complex_Parts(lua_State *L)
    {
    complex_t z; 
    checkcomplex(L, 1, &z);
    lua_pushnumber(L, creal(z));
    lua_pushnumber(L, cimag(z));
    return 2;
    }

int complex_Conj(lua_State *L)
    {
    complex_t z; 
    checkcomplex(L, 1, &z);
    return pushcomplex(L, conj(z));
    }

static const struct luaL_Reg Metamethods[] = 
    {
        { "__tostring", ToString },
        { "__concat", Concat },
        { "__unm", Unm },
        { "__add", Add },
        { "__sub", Sub },
        { "__mul", Mul },
        { "__div", Div },
        { "__pow", Pow },
        { NULL, NULL } /* sentinel */
    };

static const struct luaL_Reg Methods[] = 
    {
        { "parts", complex_Parts },
        { "conj", complex_Conj },
        { "norm", complex_Norm },
        { "norm2", complex_Norm2 },
        { "normalize", complex_Normalize },
        { "inv", complex_Inv },
        { "cabs", complex_Norm },
        { "cpow", Pow },
        { "carg", Carg },
        { "cimag", Cimag },
        { "creal", Creal },
        { "csin", Csin },
        { "ccos", Ccos },
        { "ctan", Ctan },
        { "casin", Casin },
        { "cacos", Cacos },
        { "catan", Catan },
        { "csinh", Csinh },
        { "ccosh", Ccosh },
        { "ctanh", Ctanh },
        { "casinh", Casinh },
        { "cacosh", Cacosh },
        { "catanh", Catanh },
        { "cproj", Cproj },
        { "clog", Clog },
        { "cexp", Cexp },
        { "csqrt", Csqrt },
        { NULL, NULL } /* sentinel */
    };



/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "complex", Complex },
        { "iscomplex", IsComplex },
//      { "conj", complex_Conj }, --> in funcs.c
        { "cabs", complex_Norm },
        { "cpow", Pow },
        { "carg", Carg },
        { "cimag", Cimag },
        { "creal", Creal },
        { "csin", Csin },
        { "ccos", Ccos },
        { "ctan", Ctan },
        { "casin", Casin },
        { "cacos", Cacos },
        { "catan", Catan },
        { "csinh", Csinh },
        { "ccosh", Ccosh },
        { "ctanh", Ctanh },
        { "casinh", Casinh },
        { "cacosh", Cacosh },
        { "catanh", Catanh },
        { "cproj", Cproj },
        { "clog", Clog },
        { "cexp", Cexp },
        { "csqrt", Csqrt },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_complex(lua_State *L)
    {
    newmetatable(L, COMPLEX_MT);
    metatable_setfuncs(L, COMPLEX_MT, Metamethods, Methods);
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>src/moonglmath.h<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/****************************************************************************
 * MoonGLMATH library - C API                                               *
 ****************************************************************************/

#ifndef moonglmathDEFINED
#define moonglmathDEFINED

#include <complex.h>
#include <lua.h>
#include "lualib.h"
#include "lauxlib.h"
#include "compat-5.3.h"

#define MOONGLMATH_VERSION      "0.6"


/*---------------------------------------------------------------------------*
 | Types, check/test/push                                                    |
 *---------------------------------------------------------------------------*/

typedef double moonglmath_vec_t[4];
typedef double moonglmath_box_t[8];
typedef double moonglmath_mat_t[4][4];
typedef double moonglmath_quat_t[4];
typedef double complex moonglmath_complex_t;

/* Metatables names (keys in the Lua registry) */
#define MOONGLMATH_VEC_MT "moonglmath_vec"
#define MOONGLMATH_BOX_MT "moonglmath_box"
#define MOONGLMATH_MAT_MT "moonglmath_mat"
#define MOONGLMATH_QUAT_MT "moonglmath_quat"
#define MOONGLMATH_COMPLEX_MT "moonglmath_complex"

int moonglmath_testmetatable(lua_State *L, int arg, const char *metatable);
int moonglmath_checkmetatable(lua_State *L, int arg, const char *metatable);

#define moonglmath_isvec(L, arg) moonglmath_testmetatable((L), arg, MOONGLMATH_VEC_MT)
#define moonglmath_isbox(L, arg) moonglmath_testmetatable((L), arg, MOONGLMATH_BOX_MT)
#define moonglmath_ismat(L, arg) moonglmath_testmetatable((L), arg, MOONGLMATH_MAT_MT)
#define moonglmath_isquat(L, arg) moonglmath_testmetatable((L), arg, MOONGLMATH_QUAT_MT)
#define moonglmath_iscomplex(L, arg) moonglmath_testmetatable((L), arg, MOONGLMATH_COMPLEX_MT)

int moonglmath_testvec(lua_State *L, int arg, moonglmath_vec_t v, size_t *size, unsigned int *isrow);
int moonglmath_checkvec(lua_State *L, int arg, moonglmath_vec_t v, size_t *size, unsigned int *isrow);
int moonglmath_pushvec(lua_State *L, moonglmath_vec_t v, size_t vsize, size_t size, unsigned int isrow);

int moonglmath_testbox(lua_State *L, int arg, moonglmath_box_t b, size_t *dim);
int moonglmath_checkbox(lua_State *L, int arg, moonglmath_box_t b, size_t *dim);
int moonglmath_pushbox(lua_State *L, moonglmath_box_t b, size_t dim);

int moonglmath_testmat(lua_State *L, int arg, moonglmath_mat_t m, size_t *nr, size_t *nc);
int moonglmath_checkmat(lua_State *L, int arg, moonglmath_mat_t m, size_t *nr, size_t *nc);
int moonglmath_pushmat(lua_State *L, moonglmath_mat_t m, size_t mr, size_t mc, size_t nr, size_t nc);

int moonglmath_testquat(lua_State *L, int arg, moonglmath_quat_t q);
int moonglmath_checkquat(lua_State *L, int arg, moonglmath_quat_t q);
int moonglmath_pushquat(lua_State *L, moonglmath_quat_t q);

int moonglmath_testcomplex(lua_State *L, int arg, moonglmath_complex_t *z);
int moonglmath_checkcomplex(lua_State *L, int arg, moonglmath_complex_t *z);
int moonglmath_pushcomplex(lua_State *L, moonglmath_complex_t z);

/*---------------------------------------------------------------------------*
 | Vector                                                                    |
 *---------------------------------------------------------------------------*/

#define moonglmath_vec_clear(v)    memset((v), 0, sizeof(moonglmath_vec_t))
#define moonglmath_vec_copy(dst,v) memcpy((dst), (v), sizeof(moonglmath_vec_t))
void moonglmath_vec_unm(moonglmath_vec_t dst, moonglmath_vec_t v, size_t n);
void moonglmath_vec_add(moonglmath_vec_t dst, moonglmath_vec_t v1, moonglmath_vec_t v2, size_t n);
void moonglmath_vec_sub(moonglmath_vec_t dst, moonglmath_vec_t v1, moonglmath_vec_t v2, size_t n);
double moonglmath_vec_norm(moonglmath_vec_t v, size_t n);
double moonglmath_vec_norm2(moonglmath_vec_t v, size_t n);
void moonglmath_vec_normalize(moonglmath_vec_t v, size_t n);
void moonglmath_vec_div(moonglmath_vec_t dst, moonglmath_vec_t v, double s, size_t n);
double moonglmath_vec_dot(moonglmath_vec_t v1, moonglmath_vec_t v2, size_t n);
void moonglmath_vec_vxs(moonglmath_vec_t dst, moonglmath_vec_t v, double s, size_t n);
void moonglmath_vec_vxv(moonglmath_mat_t dst, moonglmath_vec_t v1, moonglmath_vec_t v2, size_t n);
void moonglmath_vec_cross(moonglmath_vec_t dst, moonglmath_vec_t v1, moonglmath_vec_t v2);
void moonglmath_vec_clamp(moonglmath_vec_t dst, moonglmath_vec_t v, moonglmath_vec_t minv, moonglmath_vec_t maxv, size_t n);
void moonglmath_vec_mix(moonglmath_vec_t dst, moonglmath_vec_t v1, moonglmath_vec_t v2, size_t n, double k);
void moonglmath_vec_step(moonglmath_vec_t dst, moonglmath_vec_t v, moonglmath_vec_t edge, size_t n);
void moonglmath_vec_smoothstep(moonglmath_vec_t dst, moonglmath_vec_t v, moonglmath_vec_t edge0, moonglmath_vec_t edge1, size_t n);
void moonglmath_vec_fade(moonglmath_vec_t dst, moonglmath_vec_t v, moonglmath_vec_t edge0, moonglmath_vec_t edge1, size_t n);

/*---------------------------------------------------------------------------*
 | Box                                                                       |
 *---------------------------------------------------------------------------*/

#define moonglmath_box_clear(b)    memset((b), 0, sizeof(moonglmath_box_t))
#define moonglmath_box_copy(dst,b) memcpy((dst), (b), sizeof(moonglmath_box_t))

/*---------------------------------------------------------------------------*
 | Matrix                                                                    |
 *---------------------------------------------------------------------------*/

#define moonglmath_mat_clear(m)        memset((m), 0, sizeof(moonglmath_mat_t))
#define moonglmath_mat_copy(dst,m)     memcpy((dst), (m), sizeof(moonglmath_mat_t))
void moonglmath_mat_unm(moonglmath_mat_t dst, moonglmath_mat_t m, size_t nr, size_t nc);
void moonglmath_mat_transpose(moonglmath_mat_t dst, moonglmath_mat_t m, size_t nr, size_t nc);
void moonglmath_mat_add(moonglmath_mat_t dst, moonglmath_mat_t m1, moonglmath_mat_t m2, size_t nr, size_t nc);
void moonglmath_mat_sub(moonglmath_mat_t dst, moonglmath_mat_t m1, moonglmath_mat_t m2, size_t nr, size_t nc);
void moonglmath_mat_div(moonglmath_mat_t dst, moonglmath_mat_t m, double s, size_t nr, size_t nc);
void moonglmath_mat_mul(moonglmath_mat_t dst, moonglmath_mat_t m1, moonglmath_mat_t m2, size_t nr1, size_t nc1, size_t nc2);
void moonglmath_mat_mulby(moonglmath_mat_t m1, moonglmath_mat_t m2, size_t nr1, size_t nc1, size_t nc2);
void moonglmath_mat_mxs(moonglmath_mat_t dst, moonglmath_mat_t m, double s, size_t nr, size_t nc);
void moonglmath_mat_mxv(moonglmath_vec_t dst, moonglmath_mat_t m, moonglmath_vec_t v, size_t nr, size_t nc);
void moonglmath_mat_vxm(moonglmath_vec_t dst, moonglmath_vec_t v, moonglmath_mat_t m, size_t nr, size_t nc);
double moonglmath_mat_det2(moonglmath_mat_t m);
double moonglmath_mat_det3(moonglmath_mat_t m);
double moonglmath_mat_det4(moonglmath_mat_t m);
void moonglmath_mat_adj(moonglmath_mat_t dst, moonglmath_mat_t m, size_t n);
int moonglmath_mat_inv(moonglmath_mat_t dst, moonglmath_mat_t m, size_t n);
int moonglmath_mat_clamp(moonglmath_mat_t dst, moonglmath_mat_t m, moonglmath_mat_t minm, moonglmath_mat_t maxm, size_t nr, size_t nc);
int moonglmath_mat_mix(moonglmath_mat_t dst, moonglmath_mat_t m1, moonglmath_mat_t m2, size_t nr, size_t nc, double k);
int moonglmath_mat_step(moonglmath_mat_t dst, moonglmath_mat_t m, moonglmath_mat_t edge, size_t nr, size_t nc);
int moonglmath_mat_smoothstep(moonglmath_mat_t dst, moonglmath_mat_t m, moonglmath_mat_t edge0, moonglmath_mat_t edge1, size_t nr, size_t nc);
int moonglmath_mat_fade(moonglmath_mat_t dst, moonglmath_mat_t m, moonglmath_mat_t edge0, moonglmath_mat_t edge1, size_t nr, size_t nc);

/*---------------------------------------------------------------------------*
 | Quaternion                                                                |
 *---------------------------------------------------------------------------*/

#define moonglmath_quat_clear(q)   memset((q), 0, sizeof(moonglmath_quat_t))
#define moonglmath_quat_copy(dst, q)   memcpy((dst), (q), sizeof(moonglmath_quat_t))
void moonglmath_quat_unm(moonglmath_quat_t dst, moonglmath_quat_t q);
void moonglmath_quat_add(moonglmath_quat_t dst, moonglmath_quat_t q1, moonglmath_quat_t q2);
void moonglmath_quat_sub(moonglmath_quat_t dst, moonglmath_quat_t q1, moonglmath_quat_t q2);
double moonglmath_quat_norm(moonglmath_quat_t q);
double moonglmath_quat_norm2(moonglmath_quat_t q);
void moonglmath_quat_normalize(moonglmath_quat_t q);
void moonglmath_quat_conj(moonglmath_quat_t dst, moonglmath_quat_t q); 
void moonglmath_quat_inv(moonglmath_quat_t dst, moonglmath_quat_t q);
void moonglmath_quat_div(moonglmath_quat_t dst, moonglmath_quat_t q, double s);
void moonglmath_quat_mul(moonglmath_quat_t dst, moonglmath_quat_t q, moonglmath_quat_t p);
void moonglmath_quat_qxs(moonglmath_quat_t dst, moonglmath_quat_t q, double s);
void moonglmath_quat_mix(moonglmath_quat_t dst, moonglmath_quat_t q, moonglmath_quat_t p, double t);
void moonglmath_quat_slerp(moonglmath_quat_t dst, moonglmath_quat_t q, moonglmath_quat_t p, double t);

/*---------------------------------------------------------------------------*
 | Numbers                                                                   |
 *---------------------------------------------------------------------------*/

double moonglmath_clamp(double x, double minval, double maxval);
double moonglmath_mix(double x, double y, double k);
double moonglmath_step(double x, double edge);
double moonglmath_smoothstep(double x, double edge0, double edge1);
double moonglmath_fade(double x, double edge0, double edge1);

/*---------------------------------------------------------------------------*
 | Other                                                                     |
 *---------------------------------------------------------------------------*/

/* time */
double moonglmath_now(void);

/* basic transforms */
void moonglmath_translate(moonglmath_mat_t m, double x, double y, double z);
void moonglmath_scale(moonglmath_mat_t m, double x, double y, double z);
void moonglmath_rotate_x(moonglmath_mat_t m, double rad);
void moonglmath_rotate_y(moonglmath_mat_t m, double rad);
void moonglmath_rotate_z(moonglmath_mat_t m, double rad);

/* viewing */
int moonglmath_look_at(moonglmath_mat_t dst, moonglmath_vec_t eye, moonglmath_vec_t at, moonglmath_vec_t up);
int moonglmath_ortho(moonglmath_mat_t dst, double l, double r, double b, double t, double n, double f);
int moonglmath_frustum(moonglmath_mat_t dst, double l, double r, double b, double t, double n, double f);
int moonglmath_perspective(moonglmath_mat_t dst, double fovy, double aspect, double n, double f);

#endif /* moonglmathDEFINED */



<|start_filename|>src/viewing.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Camera positioning (view matrix)                                             |
 *------------------------------------------------------------------------------*/

int look_at(mat_t dst, vec_t eye, vec_t at, vec_t up)
/* look_at(eye, at, up) 
 *
 * eye = camera position = (e1, e2, e3)
 * at  = target position
 * up  = camera 'up' direction
 *
 * NOTE: 'up' is the direction from the camera to a point above the target,
 *        on the vertical.
 *
 * d = (at - eye) : direction vector
 * n = (eye - at) = z : normal to the projection plane, oriented towards the camera
 * x = d % up = up % n : points to the right of the camera
 * y = z % x = n % x : points up fro the camera
 *  
 * M = |x1 x2 x3 0| |1 0 0 -e1|
 *     |y1 y2 y3 0|·|0 1 0 -e2|
 *     |z1 z2 z3 0| |0 0 1 -e3|
 *     |0  0  0  1| |0 0 0   1|
 *          |           |
 *       orient     translate
 */
    {

    size_t i;
    vec_t z, x, y;
    mat_t c, te;

    vec_sub(z, eye, at, 4); /* z = eye - at (normal vector = - direction vector) */
    vec_normalize(z, 4);

    vec_cross(x, up, z); /* x = up % z  (right vector) */
    vec_normalize(x, 4);

    vec_cross(y, z, x);  /* y = z % x  (up vector) */
    vec_normalize(y, 4);

    mat_clear(c);   
    /* c = x1 x2 x3  0
     *     y1 y2 y3  0
     *     z1 z2 z3  0
     *      0  0  0  1
     */
    for(i = 0; i< 4; i ++)
        {
        c[0][i] = x[i];
        c[1][i] = y[i];
        c[2][i] = z[i];
        }
    c[3][3] = 1;

    /* dst = c * translate(-eye) */
    translate(te, -eye[0], -eye[1], -eye[2]);
    mat_mul(dst, c, te, 4, 4, 4);

    return 0;
    }

static int LookAt(lua_State *L)
    {
    mat_t m;
    vec_t eye, at, up;
    checkvec(L, 1, eye, NULL, NULL);
    checkvec(L, 2, at, NULL, NULL);
    checkvec(L, 3, up, NULL, NULL);
    look_at(m, eye, at, up);
    return pushmat(L, m, 4, 4, 4, 4);
    }


/*------------------------------------------------------------------------------*
 | Projections                                                                  |
 *------------------------------------------------------------------------------*/

int ortho(mat_t dst, double l, double r, double b, double t, double near, double far)
/* ortho(left, right, bottom, top, near,  far)
 * near=-1 and far=1 give a 2D projection
 *
 * Rfr. RTR3/4.6.1
 *
 * The viewing parallelepiped is: 
 * x: left .. right
 * y: bottom .. up
 * z: -near .. -far
 *
 * The camera is positioned at the origin, pointing to the -z axis (x=right, y=up)
 * and the projection plane is the x-y plane (or, equivalently, any plane parallel
 * to x-y, since the projectors are parallel to the z axis).
 *
 * M =  |2/(r-l)  0    0     0| |1 0 0 -(l+r)/2| = |2/(r-l)  0     0    -(r+l)/(r-l)|
 *      |  0   2/(t-b) 0     0|*|0 1 0 -(t+b)/2|   |  0   2/(t-b)  0    -(t+b)/(t-b)|
 *      |  0      0  2/(f-n) 0| |0 0 1 -(f+n)/2|   |  0     0   2/(f-n) -(f+n)/(f-n)|
 *      |  0      0    0     1| |0 0 0     1   |   |  0     0      0         1      |
 *           scaling               translation
 */
    {
    double n, f;
    n = -near;
    f = -far;
    mat_clear(dst);
    dst[0][0] = 2.0/(r-l);
    dst[0][3] = -(r+l)/(r-l);
    dst[1][1] = 2.0/(t-b);
    dst[1][3] = -(t+b)/(t-b);
    dst[2][2] = 2.0/(f-n);
    dst[2][3] = -(f+n)/(f-n);
    dst[3][3] = 1.0;
    return 0;
    }

int frustum(mat_t dst, double l, double r, double b, double t, double n, double f)
    {
    mat_clear(dst);
    dst[0][0] = 2.0*n/(r-l);
    dst[0][2] = (r+l)/(r-l);
    dst[1][1] = 2.0*n/(t-b);
    dst[1][2] = (t+b)/(t-b);
    dst[2][2] = -(f+n)/(f-n);
    dst[2][3] = -2.0*f*n/(f-n);
    dst[3][2] = -1.0;
    return 0;
    }

int perspective(mat_t dst, double fovy, double aspect, double n, double f)
    {
    double t = tan(fovy/2) * n; /* top */
    double r = t * aspect; /* right */
    mat_clear(dst);
    dst[0][0] = n/r;
    dst[1][1] = n/t;
    dst[2][2] = -(f+n)/(f-n);
    dst[2][3] = -2.0*f*n/(f-n);
    dst[3][2] = -1.0;
    return 0;
    }


static int Ortho(lua_State *L)
    {
    mat_t m;
    double l = luaL_checknumber(L, 1); /* left */
    double r = luaL_checknumber(L, 2); /* right */
    double b = luaL_checknumber(L, 3); /* bottom */
    double t = luaL_checknumber(L, 4); /* top */
    double n = luaL_optnumber(L, 5, -1.0); /* near */
    double f = luaL_optnumber(L, 6, 1.0); /* far */
    ortho(m, l, r, b, t, n, f);
    return pushmat(L, m, 4, 4, 4, 4);
    }

static int Frustum(lua_State *L)
    {
    mat_t m;
    double l = luaL_checknumber(L, 1); /* left */
    double r = luaL_checknumber(L, 2); /* right */
    double b = luaL_checknumber(L, 3); /* bottom */
    double t = luaL_checknumber(L, 4); /* top */
    double n = luaL_checknumber(L, 5); /* near */
    double f = luaL_checknumber(L, 6); /* far */
    frustum(m, l, r, b, t, n, f);
    return pushmat(L, m, 4, 4, 4, 4);
    }

static int Perspective(lua_State *L)
/* perspective(fovy, aspect, near, far)
 */
    {
    mat_t m;
    double fovy = luaL_checknumber(L, 1); /* radians */
    double aspect = luaL_checknumber(L, 2);
    double n = luaL_checknumber(L, 3); /* near */
    double f = luaL_checknumber(L, 4); /* far */
    perspective(m, fovy, aspect, n, f);
    return pushmat(L, m, 4, 4, 4, 4);
    }


/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "look_at", LookAt },
        { "ortho", Ortho },
        { "frustum", Frustum },
        { "perspective", Perspective },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_viewing(lua_State *L)
    {
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>moonglmath/utils.lua<|end_filename|>
-- The MIT License (MIT)
--
-- Copyright (c) 2016 <NAME>
--
-- Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--

-- 
-- Adds named-components access to MoonGLMATH boxes
-- ( v.minx becomes an alias for b[1], v.maxx becomes an alias for b[2], and so on).
--

--local glmath = require("moonglmath")
--local mt = getmetatable(glmath.box2())
do
local glmath = moonglmath

local function dumpdata(data, filename, mode)
-- Dumps data in a file to be used with gnuplot
-- (eg. gnuplot> plot "data.log" using 1:2 with lines)
-- 'data' = sequence of numbers (array without gaps starting from index=1)
-- 'filename'= name of file where to dump the data
   local file = assert(io.open(filename, mode or "w"))
   for i,v in ipairs(data) do
      file:write(string.format("%u %.9f\n",i,v))
   end
   file:close()
end

local function stats(data)
-- Computes mean, variax, minimum and maximum over
-- the sequence of numbers contained in data
   local max,min = 0, math.huge
   local mean, delta, m2, var = 0, 0, 0, 0
   for i=1,#data do 
      local d = data[i]
      if d < min then min = d end
      if d > max then max = d end
      delta = d - mean
      mean = mean + delta/i
      m2 = m2 + delta*(d-mean)
   end
   if #data > 1 then
      var = m2 / (#data-1)
   end
   return  mean, var, min, max
end

moonglmath.stats = stats
moonglmath.dumpdata = dumpdata

end


<|start_filename|>src/enums.h<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2018 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef enumsDEFINED
#define enumsDEFINED

/* enums.c */
#define enums_free_all moonglmath_enums_free_all
void enums_free_all(lua_State *L);
#define enums_test moonglmath_enums_test
uint32_t enums_test(lua_State *L, uint32_t domain, int arg, int *err);
#define enums_check moonglmath_enums_check
uint32_t enums_check(lua_State *L, uint32_t domain, int arg);
#define enums_push moonglmath_enums_push
int enums_push(lua_State *L, uint32_t domain, uint32_t code);
#define enums_values moonglmath_enums_values
int enums_values(lua_State *L, uint32_t domain);
#define enums_checklist moonglmath_enums_checklist
uint32_t* enums_checklist(lua_State *L, uint32_t domain, int arg, uint32_t *count, int *err);
#define enums_freelist moonglmath_enums_freelist
void enums_freelist(lua_State *L, uint32_t *list);


/* Enum domains */
#define DOMAIN_ISROW                      0
#define DOMAIN_TYPE                       1

/* DOMAIN_ISROW values (vector type) */
#define MOONGLMATH_COLUMN   0
#define MOONGLMATH_ROW      1

/* Types for glmath.sizeof() & friends */
#define MOONGLMATH_TYPE_CHAR         1
#define MOONGLMATH_TYPE_UCHAR        2
#define MOONGLMATH_TYPE_SHORT        3
#define MOONGLMATH_TYPE_USHORT       4
#define MOONGLMATH_TYPE_INT          5
#define MOONGLMATH_TYPE_UINT         6
#define MOONGLMATH_TYPE_LONG         7
#define MOONGLMATH_TYPE_ULONG        8
#define MOONGLMATH_TYPE_FLOAT        9
#define MOONGLMATH_TYPE_DOUBLE       10

#define testisrow(L, arg, err) (uint32_t)enums_test((L), DOMAIN_ISROW, (arg), (err))
#define checkisrow(L, arg) (uint32_t)enums_check((L), DOMAIN_ISROW, (arg))
#define pushisrow(L, val) enums_push((L), DOMAIN_ISROW, (uint32_t)(val))
#define valuesisrow(L) enums_values((L), DOMAIN_ISROW)

#define testtype(L, arg, err) (uint32_t)enums_test((L), DOMAIN_TYPE, (arg), (err))
#define checktype(L, arg) (uint32_t)enums_check((L), DOMAIN_TYPE, (arg))
#define pushtype(L, val) enums_push((L), DOMAIN_TYPE, (uint32_t)(val))
#define valuestype(L) enums_values((L), DOMAIN_TYPE)

#if 0 /* scaffolding 6yy */
#define testxxx(L, arg, err) (uint32_t)enums_test((L), DOMAIN_XXX, (arg), (err))
#define checkxxx(L, arg) (uint32_t)enums_check((L), DOMAIN_XXX, (arg))
#define pushxxx(L, val) enums_push((L), DOMAIN_XXX, (uint32_t)(val))
#define valuesxxx(L) enums_values((L), DOMAIN_XXX)
    CASE(xxx);

#endif

#endif /* enumsDEFINED */




<|start_filename|>src/box.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Check and push                                                               |
 *------------------------------------------------------------------------------*/

int testbox(lua_State *L, int arg, box_t b, size_t *dim)
/* Tests if the element at arg is a box and sets b and *dim accordingly
 * (unless they are passed as 0).
 */
    {
    size_t i;
    size_t dim_;
    if(!testmetatable(L, arg, BOX_MT)) return 0;

    lua_getfield(L, arg, "dimensions");   
    dim_ = luaL_checkinteger(L, -1);
    lua_pop(L, 1);
    checkboxdim(L, dim_);

    if(dim != NULL) *dim = dim_;
    if(b != NULL)
        {
        box_clear(b);
        for(i=0; i < 2*dim_; i++)
            {
            lua_geti(L, arg, i+1);
            b[i] = luaL_checknumber(L, -1);
            lua_pop(L, 1);
            }
        }
    return 1;
    }

int checkbox(lua_State *L, int arg, box_t b, size_t *dim)
/* Same as testbox(), but raises a error if the test fails.
 */
    {
    if(!testbox(L, arg, b, dim))
        return luaL_argerror(L, arg, lua_pushfstring(L, "%s expected", BOX_MT));
    return 1;
    }


int pushbox(lua_State *L, box_t b, size_t dim)
/* dim = 2 or 3
 */
    {
    size_t i;
    checkboxdim(L, dim);
    lua_newtable(L);
    setmetatable(L, BOX_MT);
    for(i=0; i<2*dim; i++)
        {
        lua_pushnumber(L, b[i]);
        lua_seti(L, -2, i+1);
        }
    lua_pushinteger(L, dim);
    lua_setfield(L, -2, "dimensions");
    return 1;
    }

/*------------------------------------------------------------------------------*
 | Box                                                                          |
 *------------------------------------------------------------------------------*/

static int Box(lua_State *L, size_t dim)
/* creates a box of dimensions 'dim', from a box or a list of values 
 * the size is adapted by discarding exceeding values or adding zeros
 * in lieu of missing values.
 * boxN(b)
 * boxN([x1 ,[x2,...[,x2N]]])
 */
    {
    box_t b;
    size_t bdim, i, arg;
    arg = 1;
    if(testbox(L, arg, b, &bdim))
        return pushbox(L, b, bdim);
    checkboxdim(L, dim);
    for(i = 0; i < 2*dim; i++)
        b[i] = luaL_optnumber(L, arg++, 0);
    return pushbox(L, b, dim);
    }

static int Box2(lua_State *L) { return Box(L, 2); }
static int Box3(lua_State *L) { return Box(L, 3); }

static int IsBox(lua_State *L, size_t dim)
    {
    size_t bdim;
    if(!testbox(L, 1, NULL, &bdim))
        lua_pushboolean(L, 0);
    else
        lua_pushboolean(L, (bdim==dim));
    return 1;
    }
    
static int IsBox2(lua_State *L) { return IsBox(L, 2); }
static int IsBox3(lua_State *L) { return IsBox(L, 3); }

/*------------------------------------------------------------------------------*
 | ToString                                                                     |
 *------------------------------------------------------------------------------*/

static int ToString_(lua_State *L, box_t b, size_t dim)
/* With snprintf because lua_pushfstring does not support the %g conversion specifier */
    {
#define SZ 512
#define space (SZ-p)
    char str[SZ];
    int p=0;
    switch(dim)
        {
        case 2: p = snprintf(str, space, "[ "FMT", "FMT", "FMT", "FMT" ]", 
                                                b[0], b[1], b[2], b[3]); break;
        case 3: p = snprintf(str, space, "[ "FMT", "FMT", "FMT", "FMT", "FMT", "FMT" ]", 
                                                b[0], b[1], b[2], b[3], b[4], b[5]); break;
        default:
            return luaL_error(L, UNEXPECTED_ERROR);
        }
    if(space<0)
        { 
        /* truncate */
        p = SZ - 5; 
        p+=snprintf(str+p, space, " ...");
        lua_pushlstring(L, str, p);
        return 1;
        }
    lua_pushlstring(L, str, p);
    return 1;
#undef space
#undef SZ
    }

static int ToString(lua_State *L)
    {
    box_t b;
    size_t dim;
    checkbox(L, 1, b, &dim);
    return ToString_(L, b, dim);
    }


static int Concat(lua_State *L)
    {
    box_t b;
    size_t dim;
    if(testbox(L, 1, b, &dim))
        {
        ToString_(L, b, dim);
        lua_pushvalue(L, 2);
        }
    else if(testbox(L, 2, b, &dim))
        {
        lua_pushvalue(L, 1);
        ToString_(L, b, dim);
        }
    else 
        return unexpected(L);
    lua_concat(L, 2);
    return 1;
    }


/*------------------------------------------------------------------------------*
 | Non-Lua functions (for internal use)                                         |
 *------------------------------------------------------------------------------*/

//@@TBD

/*------------------------------------------------------------------------------*
 | Metamethods                                                                  |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Metamethods[] = 
    {
        { "__tostring", ToString },
        { "__concat", Concat },
        { NULL, NULL } /* sentinel */
    };

static const struct luaL_Reg Methods[] = 
    {
        { NULL, NULL } /* sentinel */
    };


/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "box2", Box2 },
        { "box3", Box3 },
        { "isbox2", IsBox2 },
        { "isbox3", IsBox3 },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_box(lua_State *L)
    {
    newmetatable(L, BOX_MT);
    metatable_setfuncs(L, BOX_MT, Metamethods, Methods);
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>src/mat.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"


/*------------------------------------------------------------------------------*
 | Check and push                                                               |
 *------------------------------------------------------------------------------*/

int testmat(lua_State *L, int arg, mat_t m, size_t *nr, size_t *nc)
    {
    int row;
    size_t i, j, nr_, nc_;
    if(!testmetatable(L, arg, MAT_MT))
        return 0;

    lua_getfield(L, arg, "rows");   
    nr_ = luaL_checkinteger(L, -1);
    lua_pop(L, 1);
    lua_getfield(L, arg, "columns");    
    nc_ = luaL_checkinteger(L, -1);
    lua_pop(L, 1);
    checkmatsize(L, nr_, nc_);

    if(nr) *nr = nr_;
    if(nc) *nc = nc_;
    if(m)
        {
        for(i=0; i < nr_; i++)
            {
            if(lua_geti(L, arg, i+1) != LUA_TTABLE)
                return luaL_error(L, "malformed matrix");
            row = lua_gettop(L);
            for(j=0; j < nc_; j++)
                {
                lua_geti(L, row, j+1);
                m[i][j] = luaL_checknumber(L, -1);
                lua_pop(L, 1);
                }
            lua_pop(L, 1);
            }
        }
    return 1;
    }

int checkmat(lua_State *L, int arg, mat_t m, size_t *nr, size_t *nc)
/* Same as testmat(), but raises a error if the test fails.
 */
    {
    if(!testmat(L, arg, m, nr, nc))
        return luaL_argerror(L, arg, lua_pushfstring(L, "%s expected", MAT_MT));
    return 1;
    }

int pushmat(lua_State *L, mat_t m, size_t mr, size_t mc, size_t nr, size_t nc)
/* mr, mc = no. of valid colums/rows in m
 */
    {
    size_t i, j;
    checkmatsize(L, nr, nc);
    lua_newtable(L);
    setmetatable(L, MAT_MT);
    for(i=0; i<nr; i++)
        {
        lua_newtable(L); /* row i+1 */
        for(j=0; j<nc; j++)
            {
            lua_pushnumber(L, (i < mr) && (j < mc) ? m[i][j] : 0);
            lua_seti(L, -2, j+1);
            }
        lua_seti(L, -2, i+1);
        }
    for(i=nr; i<4; i++)
        {
        lua_newtable(L); /* empty rows */
        lua_seti(L, -2, i+1);
        }
    lua_pushinteger(L, nr);
    lua_setfield(L, -2, "rows");
    lua_pushinteger(L, nc);
    lua_setfield(L, -2, "columns");
    return 1;
    }

/*------------------------------------------------------------------------------*
 | Mat                                                                          |
 *------------------------------------------------------------------------------*/

static int Matfromvecs(lua_State *L, size_t nr, size_t nc, unsigned int row)
/* if row=1, expects all row vectors
 * if row=0, expects all column vectors
 */
    {
    size_t i,j, n;  
    mat_t m;
    vec_t v[4];
    size_t size[4];
    unsigned int isrow[4];
    
    for(i=0; i<4; i++)
        vec_clear(v[i]);
    
    n = row==1 ? nr : nc;
    for(i=0; i < n; i++)
        {
        if(testvec(L, i+1, v[i], &size[i], &isrow[i]) && (isrow[i] != row))
            return luaL_argerror(L, i+i, "expected all row or all column vectors");
        }

    if(row)
        {
        /* v[i] = i-th row */
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                m[i][j] = v[i][j];
        }
    else
        {
        /* v[j] = j-th column */
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                m[i][j] = v[j][i];
        }
    return pushmat(L, m, nr, nc, nr, nc);
    }


static int Mat(lua_State *L, size_t nr, size_t nc)
/* mat()  -> square identity
 * mat(m)  m=matrix (any size)
 * mat(v1,...,vnr) nr row vectors,
 * mat(v1,...,vnc) nc column vectors,
 * mat(val1, val2, ...)  values in row-major order
 */
    {
    mat_t m;
    size_t mr, mc, i, j, arg;
    unsigned int isrow;
    checkmatsize(L, nr, nc);
    arg = 1;
    if(lua_isnoneornil(L, arg)) /* square identity (or all zeros if nr != nc) */
        {
        mat_clear(m);
        if(nr == nc)
            for(i = 0; i< nr; i++) m[i][i] = 1;
        return pushmat(L, m, nr, nc, nr, nc);
        }

    if(testmat(L, arg, m, &mr, &mc)) /* initialization from matrix */
        return pushmat(L, m, mr, mc, nr, nc);

    if(testvec(L, arg, NULL, NULL, &isrow)) /*initialization from vectors */
        return Matfromvecs(L, nr, nc, isrow);

    checkmatsize(L, nr, nc);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m[i][j] = luaL_optnumber(L, arg++, 0);
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Mat2(lua_State *L) { return Mat(L, 2, 2); }
static int Mat3(lua_State *L) { return Mat(L, 3, 3); }
static int Mat4(lua_State *L) { return Mat(L, 4, 4); }
static int Mat2x3(lua_State *L) { return Mat(L, 2, 3); }
static int Mat3x2(lua_State *L) { return Mat(L, 3, 2); }
static int Mat2x4(lua_State *L) { return Mat(L, 2, 4); }
static int Mat4x2(lua_State *L) { return Mat(L, 4, 2); }
static int Mat3x4(lua_State *L) { return Mat(L, 3, 4); }
static int Mat4x3(lua_State *L) { return Mat(L, 4, 3); }

static int IsMat(lua_State *L, size_t nr, size_t nc)
    {
    size_t nr_, nc_;
    if(!testmat(L, 1, NULL, &nr_, &nc_))
        lua_pushboolean(L, 0);
    else
        lua_pushboolean(L, (nr_==nr) && (nc_==nc));
    return 1;
    }
    
static int IsMat2(lua_State *L) { return IsMat(L, 2, 2); }
static int IsMat3(lua_State *L) { return IsMat(L, 3, 3); }
static int IsMat4(lua_State *L) { return IsMat(L, 4, 4); }
static int IsMat2x3(lua_State *L) { return IsMat(L, 2, 3); }
static int IsMat3x2(lua_State *L) { return IsMat(L, 3, 2); }
static int IsMat2x4(lua_State *L) { return IsMat(L, 2, 4); }
static int IsMat4x2(lua_State *L) { return IsMat(L, 4, 2); }
static int IsMat3x4(lua_State *L) { return IsMat(L, 3, 4); }
static int IsMat4x3(lua_State *L) { return IsMat(L, 4, 3); }


/*------------------------------------------------------------------------------*
 | ToString                                                                     |
 *------------------------------------------------------------------------------*/

static int ToString_(lua_State *L, mat_t m, size_t nr, size_t nc)
/* With snprintf because lua_pushfstring does not support the %g conversion specifier */
    {
#define SZ 512
#define space (SZ-p)
    char str[SZ];
    int p=0;
    size_t i;
    p += snprintf(str, space, "{");
    for(i=0; i < nr; i++)
        {
        switch(nc)
            {
            case 2: p+=snprintf(str+p, space, "{ "FMT", "FMT" }, ", 
                            m[i][0], m[i][1]); break;
            case 3: p+=snprintf(str+p, space, "{ "FMT", "FMT", "FMT" }, ",
                            m[i][0], m[i][1], m[i][2]); break;
            case 4: p+=snprintf(str+p, space, "{ "FMT", "FMT", "FMT", "FMT" }, ", 
                            m[i][0], m[i][1], m[i][2], m[i][3]); break;
            default:
                return luaL_error(L, UNEXPECTED_ERROR);
            }
        if(space<0)
            { 
            /* truncate */
            p = SZ - 5; 
            p+=snprintf(str+p, space, " ...");
            lua_pushlstring(L, str, p);
            return 1;
            }
        }
    p-=2; /* strip the last separator */
    p+=snprintf(str+p, space, "}");
    lua_pushlstring(L, str, p);
    return 1;
#undef space
#undef SZ
    }

static int ToString(lua_State *L)
    {
    size_t nr, nc;
    mat_t m;
    checkmat(L, 1, m, &nr, &nc);
    return ToString_(L, m, nr, nc);
    }

static int Concat(lua_State *L)
    {
    size_t nr, nc;
    mat_t m;
//  printf("%s %s\n", lua_typename(L, lua_type(L, 1)), lua_typename(L, lua_type(L, 2)));
    if(testmat(L, 1, m, &nr, &nc))
        {
        ToString_(L, m, nr, nc);
        lua_pushvalue(L, 2);
        }
    else if(testmat(L, 2, m, &nr, &nc))
        {
        lua_pushvalue(L, 1);
        ToString_(L, m, nr, nc);
        }
    else 
        return unexpected(L);
    lua_concat(L, 2);
    return 1;
    }


/*------------------------------------------------------------------------------*
 | Non-Lua Functions (for internal use)                                         |
 *------------------------------------------------------------------------------*/

/* determinant */
#define det2_(a,b,c,d) ((a)*(d) - (c)*(b))
#define det3_(a,b,c,d,e,f,g,h,i)    \
    ((a)*det2_((e),(f),(h),(i))     \
    -(b)*det2_((d),(f),(g),(i))     \
    + (c)*det2_((d),(e),(g),(h)))
#define det4_(a,b,c,d,e,f,g,h,i,l,m,n,o,p,q,r)      \
    ((a)*det3_((f),(g),(h),(l),(m),(n),(p),(q),(r)) \
    -(b)*det3_((e),(g),(h),(i),(m),(n),(o),(q),(r)) \
    +(c)*det3_((e),(f),(h),(i),(l),(n),(o),(p),(r)) \
    -(d)*det3_((e),(f),(g),(i),(l),(m),(o),(p),(q)))

#define det2(M) det2_((M)[0][0],(M)[0][1],(M)[1][0],(M)[1][1])
#define det3(M) det3_((M)[0][0],(M)[0][1],(M)[0][2],    \
                      (M)[1][0],(M)[1][1],(M)[1][2],    \
                      (M)[2][0],(M)[2][1],(M)[2][2])
#define det4(M) det4_((M)[0][0],(M)[0][1],(M)[0][2],(M)[0][3],  \
                      (M)[1][0],(M)[1][1],(M)[1][2],(M)[1][3],  \
                      (M)[2][0],(M)[2][1],(M)[2][2],(M)[2][3],  \
                      (M)[3][0],(M)[3][1],(M)[3][2],(M)[3][3])

double mat_det2(mat_t m)
    { return det2(m); }

double mat_det3(mat_t m)
    { return det3(m); }

double mat_det4(mat_t m)
    { return det4(m); }

void mat_unm(mat_t dst, mat_t m, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = -m[i][j];
    }

void mat_transpose(mat_t dst, mat_t m, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = m[j][i];
    }

void mat_add(mat_t dst, mat_t m1, mat_t m2, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = m1[i][j] + m2[i][j];
    }

void mat_sub(mat_t dst, mat_t m1, mat_t m2, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = m1[i][j] - m2[i][j];
    }

void mat_div(mat_t dst, mat_t m, double s, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = m[i][j]/s;
    }

void mat_mxs(mat_t dst, mat_t m, double s, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = m[i][j]*s;
    }


void mat_mul(mat_t dst, mat_t m1, mat_t m2, size_t nr1, size_t nc1, size_t nc2) /* nr1=nc1 */
/* dst = m1 * m2  
 * (nr1 x nc2) = (nr1 x nc1) *(nc1 x nc2)
 */
    {
    size_t i, j, k;
    double s;
    for(i=0; i < nr1; i++)
        for(j=0; j < nc2; j++)
            {
            s = 0;
            for(k=0; k < nc1; k++)
                s += m1[i][k] * m2[k][j];
            dst[i][j] = s;
            }
    }

void mat_mulby(mat_t m1, mat_t m2, size_t nr1, size_t nc1, size_t nc2) /* nr1=nc1 */
/* m1 = m1 * m2  (in place)
 * (nr1 x nc2) = (nr1 x nc1) *(nc1 x nc2)
 */
    {
    size_t i, j, k;
    double s;
    mat_t tmp;
    mat_copy(tmp, m1);
    for(i=0; i < nr1; i++)
        for(j=0; j < nc2; j++)
            {
            s = 0;
            for(k=0; k < nc1; k++)
                s += tmp[i][k] * m2[k][j];
            m1[i][j] = s;
            }
    }


void mat_mxv(vec_t dst, mat_t m, vec_t v, size_t nr, size_t nc)
/* m is an nr x nc matrix
 * v is an nc column vector
 * dst is an nr column vector  (nr x nc) * (nc x 1) = (nr x 1)
 */
    {
    size_t i, j;
    double s;
    for(i=0; i < nr; i++)
        {
        s = 0;
        for(j=0; j < nc; j++)
            s += (m[i][j] * v[j]);
        dst[i] = s;
        }
    }

void mat_vxm(vec_t dst, vec_t v, mat_t m, size_t nr, size_t nc)
/* v is an nr row vector
 * m is an nr x nc matrix
 * dst is an nc row vector  (1 x nr) x (nr x nc) = (1 x nc)
 */
    {
    size_t i, j;
    double s;
    for(i=0; i < nc; i++)
        {
        s = 0;
        for(j=0; j < nr; j++)
            s += (v[j] * m[j][i]);
        dst[i] = s;
        }
    }

void mat_adj(mat_t dst, mat_t m, size_t n)
    {
    if(n==2)
        {
        dst[0][0] = m[1][1];
        dst[0][1] = -m[0][1];
        dst[1][0] = -m[1][0];
        dst[1][1] = m[0][0];
        }
    else if(n==3)
        {
        dst[0][0] = det2_(m[1][1], m[1][2], m[2][1], m[2][2]);
        dst[0][1] = det2_(m[0][2], m[0][1], m[2][2], m[2][1]);
        dst[0][2] = det2_(m[0][1], m[0][2], m[1][1], m[1][2]);
        dst[1][0] = det2_(m[1][2], m[1][0], m[2][2], m[2][0]);
        dst[1][1] = det2_(m[0][0], m[0][2], m[2][0], m[2][2]);
        dst[1][2] = det2_(m[0][2], m[0][0], m[1][2], m[1][0]);
        dst[2][0] = det2_(m[1][0], m[1][1], m[2][0], m[2][1]);
        dst[2][1] = det2_(m[0][1], m[0][0], m[2][1], m[2][0]);
        dst[2][2] = det2_(m[0][0], m[0][1], m[1][0], m[1][1]);
        }
    else //if(nr==4)
        {
        dst[0][0]=det3_(m[1][1],m[1][2],m[1][3],m[2][1],m[2][2],m[2][3],m[3][1],m[3][2],m[3][3]);
        dst[0][1]=-det3_(m[0][1],m[0][2],m[0][3],m[2][1],m[2][2],m[2][3],m[3][1],m[3][2],m[3][3]);
        dst[0][2]=det3_(m[0][1],m[0][2],m[0][3],m[1][1],m[1][2],m[1][3],m[3][1],m[3][2],m[3][3]);
        dst[0][3]=-det3_(m[0][1],m[0][2],m[0][3],m[1][1],m[1][2],m[1][3],m[2][1],m[2][2],m[2][3]);
        dst[1][0]=-det3_(m[1][0],m[1][2],m[1][3],m[2][0],m[2][2],m[2][3],m[3][0],m[3][2],m[3][3]);
        dst[1][1]=det3_(m[0][0],m[0][2],m[0][3],m[2][0],m[2][2],m[2][3],m[3][0],m[3][2],m[3][3]);
        dst[1][2]=-det3_(m[0][0],m[0][2],m[0][3],m[1][0],m[1][2],m[1][3],m[3][0],m[3][2],m[3][3]);
        dst[1][3]=det3_(m[0][0],m[0][2],m[0][3],m[1][0],m[1][2],m[1][3],m[2][0],m[2][2],m[2][3]);
        dst[2][0]=det3_(m[1][0],m[1][1],m[1][3],m[2][0],m[2][1],m[2][3],m[3][0],m[3][1],m[3][3]);
        dst[2][1]=-det3_(m[0][0],m[0][1],m[0][3],m[2][0],m[2][1],m[2][3],m[3][0],m[3][1],m[3][3]);
        dst[2][2]=det3_(m[0][0],m[0][1],m[0][3],m[1][0],m[1][1],m[1][3],m[3][0],m[3][1],m[3][3]);
        dst[2][3]=-det3_(m[0][0],m[0][1],m[0][3],m[1][0],m[1][1],m[1][3],m[2][0],m[2][1],m[2][3]);
        dst[3][0]=-det3_(m[1][0],m[1][1],m[1][2],m[2][0],m[2][1],m[2][2],m[3][0],m[3][1],m[3][2]);
        dst[3][1]=det3_(m[0][0],m[0][1],m[0][2],m[2][0],m[2][1],m[2][2],m[3][0],m[3][1],m[3][2]);
        dst[3][2]=-det3_(m[0][0],m[0][1],m[0][2],m[1][0],m[1][1],m[1][2],m[3][0],m[3][1],m[3][2]);
        dst[3][3]=det3_(m[0][0],m[0][1],m[0][2],m[1][0],m[1][1],m[1][2],m[2][0],m[2][1],m[2][2]);
        }
    }

int mat_inv(mat_t dst, mat_t m, size_t n)
    {
    size_t i, j;
    double d;
    if(n==2)
        d = det2(m);
    else if(n==3)
        d = det3(m);
    else //if(n==4)
        d = det4(m);
    if(d == 0.0)
        return 0;
    mat_adj(dst, m, n);
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            dst[i][j] /= d;
    return 1;
    }

int mat_clamp(mat_t dst, mat_t m, mat_t minm, mat_t maxm, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = clamp(m[i][j], minm[i][j], maxm[i][j]);
    return 1;
    }

int mat_mix(mat_t dst, mat_t m1, mat_t m2, size_t nr, size_t nc, double k)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = mix(m1[i][j], m2[i][j], k);
    return 1;
    }

int mat_step(mat_t dst, mat_t m, mat_t edge, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = step(m[i][j], edge[i][j]);
    return 1;
    }

int mat_smoothstep(mat_t dst, mat_t m, mat_t edge0, mat_t edge1, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = smoothstep(m[i][j], edge0[i][j], edge1[i][j]);
    return 1;
    }

int mat_fade(mat_t dst, mat_t m, mat_t edge0, mat_t edge1, size_t nr, size_t nc)
    {
    size_t i, j;
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            dst[i][j] = fade(m[i][j], edge0[i][j], edge1[i][j]);
    return 1;
    }


/*------------------------------------------------------------------------------*
 | Metamethods                                                                  |
 *------------------------------------------------------------------------------*/

static int Unm(lua_State *L)
    {
    size_t i, j, nr, nc;
    mat_t m;
    checkmat(L, 1, m, &nr, &nc);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m[i][j] = -m[i][j];
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Add(lua_State *L)
    {
    size_t i, j, nr, nc, nr1, nc1;
    mat_t m, m1;
    checkmat(L, 1, m, &nr, &nc);
    checkmat(L, 2, m1, &nr1, &nc1);
    if((nr!=nr1) || (nc!=nc1))
        return luaL_error(L, OPERANDS_ERROR);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m[i][j] += m1[i][j];
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Sub(lua_State *L)
    {
    size_t i, j, nr, nc, nr1, nc1;
    mat_t m, m1;
    checkmat(L, 1, m, &nr, &nc);
    checkmat(L, 2, m1, &nr1, &nc1);
    if((nr!=nr1) || (nc!=nc1))
        return luaL_error(L, OPERANDS_ERROR);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m[i][j] -= m1[i][j];
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Mxs(lua_State *L, int sarg, int marg)
    {
    size_t i, j, nr, nc;
    mat_t m;
    double s = luaL_checknumber(L, sarg);
    checkmat(L, marg, m, &nr, &nc);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m[i][j] *= s;
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Mxv(lua_State *L) /* MxN * Nx1 = N*1 (column vector)*/
    {
    unsigned int isrow;
    size_t i, j, nr, nc, size;
    mat_t m;
    vec_t v, v1;
    double s;
    checkmat(L, 1, m, &nr, &nc);
    checkvec(L, 2, v, &size, &isrow);
    if( isrow || (size != nc))
        {
#if 0
        if((size == 3) && (nr == 4) && (nc == 4))
            {
            /* Keep only the upper left 3x3 matrix */
            nr = nc = 3;
            }
        else
#endif
            return luaL_error(L, OPERANDS_ERROR);
        }
    for(i=0; i < nr; i++)
        {
        s = 0;
        for(j=0; j < size; j++)
            s += (m[i][j] * v[j]);
        v1[i] = s;
        }
    return pushvec(L, v1, size, size, 0);
    }


static int Mul(lua_State *L)
    {
    size_t i, j, k, nr1, nc1, nr2, nc2;
    mat_t m, m1, m2;
    double s;
    if(lua_isnumber(L, 1))
        return Mxs(L, 1, 2);
    if(lua_isnumber(L, 2))
        return Mxs(L, 2, 1);
    if(testvec(L, 2, NULL, NULL, NULL))
        return Mxv(L);
    /* matrix product  NxK * KxM -> NxM  (with N,K,M  != 1) */
    checkmat(L, 1, m1, &nr1, &nc1);
    checkmat(L, 2, m2, &nr2, &nc2);
    if((nc1 != nr2))
        return luaL_error(L, OPERANDS_ERROR);
    for(i=0; i < nr1; i++)
        for(j=0; j < nc2; j++)
            {
            s = 0;
            for(k=0; k < nc1; k++)
                s += m1[i][k] * m2[k][j];
            m[i][j] = s;
            }
    pushmat(L, m, nr1, nc2, nr1, nc2);
    return 1;
    }

static int Div(lua_State *L)
    {
    size_t i, j, nr, nc;
    mat_t m;
    double s;
    checkmat(L, 1, m, &nr, &nc);
    s = luaL_checknumber(L, 2);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m[i][j] /= s;
    return pushmat(L, m, nr, nc, nr, nc);
    }

static int Pow(lua_State *L)
    {
    size_t nr, nc;
    mat_t m, dst;
    lua_Integer n, i;
    checkmat(L, 1, m, &nr, &nc);
    if((nc != nr))
        return luaL_error(L, OPERANDS_ERROR);
    n = luaL_checkinteger(L, 2);
    if(n==0) /* m^0 = identity */
        {
        mat_clear(dst);
        dst[0][0] = dst[1][1] = dst[2][2] = dst[3][3]= 1;
        }
    else 
        {
        if(n > 0)
            mat_copy(dst, m);
        else /* n < 0 */
            { 
            if(!mat_inv(dst, m, nr))
                return luaL_argerror(L, 1, "singular matrix");
            mat_copy(m, dst); 
            n = -n; 
            }
        for(i = 0; i < (n-1); i++)
            mat_mulby(dst, m, nr, nr, nr);
        }
    return pushmat(L, dst, nr, nc, nr, nc);
    }



int mat_Det(lua_State *L)
    {
    size_t nr, nc;
    mat_t m;
    checkmat(L, 1, m, &nr, &nc);
    if(nr != nc)
        return luaL_argerror(L, 1, "not a square matrix");
    if(nr==2)
        lua_pushnumber(L, det2(m));
    else if(nr==3)
        lua_pushnumber(L, det3(m));
    else //if(nr==4)
        lua_pushnumber(L, det4(m));
    return 1;
    }

int mat_Adj(lua_State *L)
    {
    size_t nr, nc;
    mat_t m, adj;
    checkmat(L, 1, m, &nr, &nc);
    if(nr != nc)
        return luaL_argerror(L, 1, "not a square matrix");
    mat_adj(adj, m, nr);
    return pushmat(L, adj, nr, nr, nr, nr);
    }

int mat_Inv(lua_State *L)
    {
    size_t nr, nc;
    mat_t m, inv;
    checkmat(L, 1, m, &nr, &nc);
    if(nr != nc)
        return luaL_argerror(L, 1, "not a square matrix");
    if(!mat_inv(inv, m, nr))
        return luaL_argerror(L, 1, "singular matrix");
    return pushmat(L, inv, nr, nr, nr, nr);
    }


int mat_Trace(lua_State *L)
    {
    size_t nr, nc, i;
    mat_t m;
    double res = 0;
    checkmat(L, 1, m, &nr, &nc);
    if(nr != nc)
        return luaL_argerror(L, 1, "not a square matrix");
    for(i = 0; i < nr; i++)
        res += m[i][i];
    lua_pushnumber(L, res);
    return 1;
    }


int mat_Transpose(lua_State *L)
    {
    size_t i, j, nr, nc;
    mat_t m, m1;
    checkmat(L, 1, m, &nr, &nc);
    for(i = 0; i < nr; i++)
        for(j = 0; j < nc; j++)
            m1[j][i] = m[i][j];
    return pushmat(L, m1, nc, nr, nc, nr);
    }

static int mat_Quat(lua_State *L)
    {
    return quat_FromMat(L);
    }

int mat_Column(lua_State *L)
    {
    mat_t m;
    vec_t v;
    size_t i, j, nr, nc;
    checkmat(L, 1, m, &nr, &nc);
    j = luaL_checkinteger(L, 2);
    if(j < 1 || j > nc)
        return luaL_argerror(L, 2, "invalid column index");
    j--;
    for(i = 0; i < nr; i++)
        v[i] = m[i][j];
    return pushvec(L, v, nr, nr, 0);
    }

int mat_Row(lua_State *L)
    {
    mat_t m;
    vec_t v;
    size_t i, j, nr, nc;
    checkmat(L, 1, m, &nr, &nc);
    i = luaL_checkinteger(L, 2);
    if(i < 1 || i > nr)
        return luaL_argerror(L, 2, "invalid row index");
    i--;
    for(j = 0; j < nc; j++)
        v[j] = m[i][j];
    return pushvec(L, v, nc, nc, 1);
    }

int mat_Clamp(lua_State *L)
    {
    mat_t dst;
    mat_t m, minm, maxm;
    size_t nr, nc, nr1, nc1;
    checkmat(L, 1, m, &nr, &nc);
    checkmat(L, 2, minm, &nr1, &nc1);
    if(nr1 != nr || nc1 != nc)
        return luaL_error(L, OPERANDS_ERROR);
    checkmat(L, 3, maxm, &nr1, &nc1);
    if(nr1 != nr || nc1 != nc)
        return luaL_error(L, OPERANDS_ERROR);
    mat_clamp(dst, m, minm, maxm, nr, nc);
    return pushmat(L, dst, nr, nc, nr, nc);
    }

int mat_Mix(lua_State *L)
    {
    mat_t dst, m1, m2;
    double k;
    size_t nr, nc, nr1, nc1;
    checkmat(L, 1, m1, &nr, &nc);
    checkmat(L, 2, m2, &nr1, &nc1);
    if(nr1 != nr || nc1 != nc)
        return luaL_error(L, OPERANDS_ERROR);
    k = luaL_checknumber(L, 3);
    mat_mix(dst, m1, m2, nr, nc, k);
    return pushmat(L, dst, nr, nc, nr, nc);
    }

int mat_Step(lua_State *L)
    {
    mat_t dst, m1, edge;
    size_t nr, nc, nr1, nc1, i, j;
    checkmat(L, 1, m1, &nr, &nc);
    if(lua_isnumber(L, 2))
        {
        double k = lua_tonumber(L, 2);
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                edge[i][j] = k;
        }
    else
        {
        checkmat(L, 2, edge, &nr1, &nc1);
        if(nr1 != nr || nc1 != nc)
            return luaL_error(L, OPERANDS_ERROR);
        }
    mat_step(dst, m1, edge, nr, nc);
    return pushmat(L, dst, nr, nc, nr, nc);
    }

int mat_Smoothstep(lua_State *L)
    {
    mat_t dst, m, edge0, edge1;
    size_t nr, nc, nr1, nc1, i, j;
    checkmat(L, 1, m, &nr, &nc);
    if(lua_isnumber(L, 2))
        {
        double k = lua_tonumber(L, 2);
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                edge0[i][j] = k;
        }
    else
        {
        checkmat(L, 2, edge0, &nr1, &nc1);
        if(nr1 != nr || nc1 != nc)
            return luaL_error(L, OPERANDS_ERROR);
        }
    if(lua_isnumber(L, 3))
        {
        double k = lua_tonumber(L, 3);
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                edge1[i][j] = k;
        }
    else
        {
        checkmat(L, 3, edge1, &nr1, &nc1);
        if(nr1 != nr || nc1 != nc)
            return luaL_error(L, OPERANDS_ERROR);
        }
    mat_smoothstep(dst, m, edge0, edge1, nr, nc);
    return pushmat(L, dst, nr, nc, nr, nc);
    }

int mat_Fade(lua_State *L)
    {
    mat_t dst, m, edge0, edge1;
    size_t nr, nc, nr1, nc1, i, j;
    checkmat(L, 1, m, &nr, &nc);
    if(lua_isnumber(L, 2))
        {
        double k = lua_tonumber(L, 2);
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                edge0[i][j] = k;
        }
    else
        {
        checkmat(L, 2, edge0, &nr1, &nc1);
        if(nr1 != nr || nc1 != nc)
            return luaL_error(L, OPERANDS_ERROR);
        }
    if(lua_isnumber(L, 3))
        {
        double k = lua_tonumber(L, 3);
        for(i=0; i<nr; i++)
            for(j=0; j<nc; j++)
                edge1[i][j] = k;
        }
    else
        {
        checkmat(L, 3, edge1, &nr1, &nc1);
        if(nr1 != nr || nc1 != nc)
            return luaL_error(L, OPERANDS_ERROR);
        }
    mat_fade(dst, m, edge0, edge1, nr, nc);
    return pushmat(L, dst, nr, nc, nr, nc);
    }


static const struct luaL_Reg Metamethods[] = 
    {
        { "__tostring", ToString },
        { "__concat", Concat },
        { "__unm", Unm },
        { "__add", Add },
        { "__sub", Sub },
        { "__mul", Mul },
        { "__div", Div },
        { "__pow", Pow },
        { NULL, NULL } /* sentinel */
    };

static const struct luaL_Reg Methods[] = 
    {
//@@ TODO: norm, normalize
        { "adj", mat_Adj },
        { "det", mat_Det },
        { "inv", mat_Inv },
        { "transpose", mat_Transpose },
        { "trace", mat_Trace },
        { "quat", mat_Quat },
        { "column", mat_Column },
        { "row", mat_Row },
        { "clamp", mat_Clamp },
        { "mix", mat_Mix },
        { "step", mat_Step },
        { "smoothstep", mat_Smoothstep },
        { "fade", mat_Fade },
        { NULL, NULL } /* sentinel */
    };


/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "mat2", Mat2 },
        { "mat3", Mat3 },
        { "mat4", Mat4 },
        { "mat2x3", Mat2x3 },
        { "mat3x2", Mat3x2 },
        { "mat2x4", Mat2x4 },
        { "mat4x2", Mat4x2 },
        { "mat3x4", Mat3x4 },
        { "mat4x3", Mat4x3 },
        { "ismat2", IsMat2 },
        { "ismat3", IsMat3 },
        { "ismat4", IsMat4 },
        { "ismat2x3", IsMat2x3 },
        { "ismat3x2", IsMat3x2 },
        { "ismat2x4", IsMat2x4 },
        { "ismat4x2", IsMat4x2 },
        { "ismat3x4", IsMat3x4 },
        { "ismat4x3", IsMat4x3 },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_mat(lua_State *L)
    {
    newmetatable(L, MAT_MT);
    metatable_setfuncs(L, MAT_MT, Metamethods, Methods);
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>examples/versions.lua<|end_filename|>
#!/usr/bin/env lua
-- MoonGLMATH example: versions.lua

local glmath = require("moonglmath")
print(_VERSION)
print(glmath._VERSION)



<|start_filename|>src/utils.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Misc utilities                                                               |
 *------------------------------------------------------------------------------*/

int noprintf(const char *fmt, ...) 
    { (void)fmt; return 0; }

int notavailable(lua_State *L, ...) 
    { NOT_AVAILABLE; }

/*------------------------------------------------------------------------------*
 | Malloc                                                                       |
 *------------------------------------------------------------------------------*/

/* We do not use malloc(), free() etc directly. Instead, we inherit the memory
 * allocator from the main Lua state instead (see lua_getallocf in the Lua manual)
 * and use that.
 *
 * By doing so, we can use an alternative malloc() implementation without recompiling
 * this library (we have needs to recompile lua only, or execute it with LD_PRELOAD
 * set to the path to the malloc library we want to use).
 */
static lua_Alloc Alloc = NULL;
static void* AllocUd = NULL;

static void malloc_init(lua_State *L)
    {
    if(Alloc) unexpected(L);
    Alloc = lua_getallocf(L, &AllocUd);
    }

static void* Malloc_(size_t size)
    { return Alloc ? Alloc(AllocUd, NULL, 0, size) : NULL; }

static void Free_(void *ptr)
    { if(Alloc) Alloc(AllocUd, ptr, 0, 0); }

void *Malloc(lua_State *L, size_t size)
    {
    void *ptr;
    if(size == 0)
        { luaL_error(L, errstring(ERR_MALLOC_ZERO)); return NULL; }
    ptr = Malloc_(size);
    if(ptr==NULL)
        { luaL_error(L, errstring(ERR_MEMORY)); return NULL; }
    memset(ptr, 0, size);
    //DBG("Malloc %p\n", ptr);
    return ptr;
    }

void *MallocNoErr(lua_State *L, size_t size) /* do not raise errors (check the retval) */
    {
    void *ptr = Malloc_(size);
    (void)L;
    if(ptr==NULL)
        return NULL;
    memset(ptr, 0, size);
    //DBG("MallocNoErr %p\n", ptr);
    return ptr;
    }

char *Strdup(lua_State *L, const char *s)
    {
    size_t len = strnlen(s, 256);
    char *ptr = (char*)Malloc(L, len + 1);
    if(len>0)
        memcpy(ptr, s, len);
    ptr[len]='\0';
    return ptr;
    }


void Free(lua_State *L, void *ptr)
    {
    (void)L;
    //DBG("Free %p\n", ptr);
    if(ptr) Free_(ptr);
    }


/*------------------------------------------------------------------------------*
 | Time utilities                                                               |
 *------------------------------------------------------------------------------*/

#if defined(LINUX)
#include <unistd.h> /* for usleep */

#if 0
static double tstosec(const struct timespec *ts)
    {
    return ts->tv_sec*1.0+ts->tv_nsec*1.0e-9;
    }
#endif

static void sectots(struct timespec *ts, double seconds)
    {
    ts->tv_sec=(time_t)seconds;
    ts->tv_nsec=(long)((seconds-((double)ts->tv_sec))*1.0e9);
    }

double now(void)
    {
#if _POSIX_C_SOURCE >= 199309L
    struct timespec ts;
    if(clock_gettime(CLOCK_MONOTONIC,&ts)!=0)
        { printf("clock_gettime error\n"); return -1; }
    return ts.tv_sec + ts.tv_nsec*1.0e-9;
#else
    struct timeval tv;
    if(gettimeofday(&tv, NULL) != 0)
        { printf("gettimeofday error\n"); return -1; }
    return tv.tv_sec + tv.tv_usec*1.0e-6;
#endif
    }

void sleeep(double seconds)
    {
#if _POSIX_C_SOURCE >= 199309L
    struct timespec ts, ts1;
    struct timespec *req, *rem, *tmp;
    sectots(&ts, seconds);
    req = &ts;
    rem = &ts1;
    while(1)
        {
        if(nanosleep(req, rem) == 0)
            return;
        tmp = req;
        req = rem;
        rem = tmp;
        }
#else
    usleep((useconds_t)(seconds*1.0e6));
#endif
    }

#define time_init(L) do { (void)L; /* do nothing */ } while(0)

#elif defined(MINGW)

#include <windows.h>

static LARGE_INTEGER Frequency;
double now(void)
    {
    LARGE_INTEGER ts;
    QueryPerformanceCounter(&ts);
    return ((double)(ts.QuadPart))/Frequency.QuadPart;
    }

void sleeep(double seconds)
    {
    DWORD msec = (DWORD)seconds * 1000;
    //if(msec < 0) return;  DWORD seems to be unsigned
    Sleep(msec);
    }

static void time_init(lua_State *L)
    {
    (void)L;
    QueryPerformanceFrequency(&Frequency);
    }

#endif


/*------------------------------------------------------------------------------*
 | Metatables handling                                                          |
 *------------------------------------------------------------------------------*/

int newmetatable(lua_State *L, const char *metatable)
    {
    luaL_newmetatable(L, metatable);
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
    lua_pop(L, 1);
    return 0;
    }

int setmetatable(lua_State *L, const char *metatable)
/* Sets the metatable of the table on top of the stack */
    {
    luaL_getmetatable(L, metatable);
    lua_setmetatable(L, -2);
    return 0;
    }

int testmetatable(lua_State *L, int arg, const char *metatable)
/* Tests the metatable of the table at index arg */
    {
    int ok = 0;
    if(lua_getmetatable(L, arg) == 0) return 0;
    luaL_getmetatable(L, metatable);
    ok = lua_compare(L, -1, -2, LUA_OPEQ);
    lua_pop(L, 2);
    return ok;
    }

int checkmetatable(lua_State *L, int arg, const char *metatable)
/* Tests the metatable of the table at index arg */
    {
    if(!testmetatable(L, arg, metatable))
        return luaL_argerror(L, arg, lua_pushfstring(L, "%s expected", metatable));
    return 1;
    }

int metatable_setfuncs(lua_State *L, const char *metatable, const luaL_Reg *metamethods, 
            const luaL_Reg *methods)
    {
    luaL_getmetatable(L, metatable);
    if(metamethods)
        luaL_setfuncs(L, metamethods, 0);
    if(methods)
        {
        luaL_getsubtable(L, -1, "__index");
        luaL_setfuncs(L, methods, 0);   
        lua_pop(L, 1);
        }
    lua_pop(L, 1);
    return 0;
    }

int checkboolean(lua_State *L, int arg)
    {
    if(!lua_isboolean(L, arg))
        return (int)luaL_argerror(L, arg, "boolean expected");
    return lua_toboolean(L, arg) ? 1 : 0;
    }

int checkoption_hint(lua_State *L, int arg, const char *def, const char *const lst[])
/* Variant of luaL_checkoption(), with an added hint in the error message */
    {
    const char *hint = NULL;
    const char *name = (def) ? luaL_optstring(L, arg, def) : luaL_checkstring(L, arg);
    int i;
    for (i=0; lst[i]; i++)
        if (strcmp(lst[i], name) == 0)  return i;

    if(lua_checkstack(L, i*2))
        {
        for(i=0; lst[i]; i++)
            {
            lua_pushfstring(L, "'%s'", lst[i]);
            lua_pushstring(L, "|");
            }
        i = i*2;
        if(i>0)
            {
            lua_pop(L, 1); /* the last separator */
            lua_concat(L, i-1);
            hint = lua_tostring(L, -1); 
            }
        }
    if(hint)
        return luaL_argerror(L, arg, lua_pushfstring(L, 
                    "invalid option '%s', valid options are: %s", name, hint));
    return luaL_argerror(L, arg, lua_pushfstring(L, "invalid option '%s'", name));
    }

int isoption(lua_State *L, int arg, const char *const lst[])
/* Variant of luaL_checkoption(), checks only and returns a boolean */
    {
    int i;
    const char *name;

    if(!lua_isstring(L, arg)) return 0;
    name = lua_tostring(L, arg);
    for (i=0; lst[i]; i++)
        if (strcmp(lst[i], name) == 0)  return 1;
    return 0;
    }


/*------------------------------------------------------------------------------*
 | Light userdata                                                               |
 *------------------------------------------------------------------------------*/

void *checklightuserdata(lua_State *L, int arg)
    {
    if(lua_type(L, arg) != LUA_TLIGHTUSERDATA)
        { luaL_argerror(L, arg, "expected lightuserdata"); return NULL; }
    return lua_touserdata(L, arg);
    }

void *optlightuserdata(lua_State *L, int arg)
    {
    if(lua_isnoneornil(L, arg))
        return NULL;
    return checklightuserdata(L, arg);
    }

void *checklightuserdataorzero(lua_State *L, int arg)
    {
    int val, isnum;
    val = lua_tointegerx(L, arg, &isnum);
    if(!isnum)
        return checklightuserdata(L, arg);
    if(val != 0)
        luaL_argerror(L, arg, "expected lightuserdata or 0");
    return NULL;
    }


/*------------------------------------------------------------------------------*
 | Internal error codes                                                         |
 *------------------------------------------------------------------------------*/

const char* errstring(int err)
    {
    switch(err)
        {
        case 0: return "success";
        case ERR_GENERIC: return "generic error";
        case ERR_TABLE: return "not a table";
        case ERR_EMPTY: return "empty list";
        case ERR_TYPE: return "invalid type";
        case ERR_VALUE: return "invalid value";
        case ERR_NOTPRESENT: return "missing";
        case ERR_MEMORY: return "out of memory";
        case ERR_MALLOC_ZERO: return "zero bytes malloc";
        case ERR_LENGTH: return "invalid length";
        case ERR_POOL: return "elements are not from the same pool";
        case ERR_BOUNDARIES: return "invalid boundaries";
        case ERR_UNKNOWN: return "unknown field name";
        default:
            return "???";
        }
    return NULL; /* unreachable */
    }

/*------------------------------------------------------------------------------*
 | Inits                                                                        |
 *------------------------------------------------------------------------------*/

void moonglmath_utils_init(lua_State *L)
    {
    malloc_init(L);
    time_init(L);
    }



<|start_filename|>src/moonglmath_local.h<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/****************************************************************************
 * MoonGLMATH library - C API redefinitions                                 *
 ****************************************************************************
 *
 * Redefines the C API functions and types without the 'moonglmath_' prefix.
 */

#ifndef moonglmath_localDEFINED
#define moonglmath_localDEFINED

#include "moonglmath.h"

#define vec_t moonglmath_vec_t
#define box_t moonglmath_box_t
#define mat_t moonglmath_mat_t
#define quat_t moonglmath_quat_t
#define complex_t moonglmath_complex_t

#define VEC_MT MOONGLMATH_VEC_MT
#define BOX_MT MOONGLMATH_BOX_MT
#define MAT_MT MOONGLMATH_MAT_MT
#define QUAT_MT MOONGLMATH_QUAT_MT
#define COMPLEX_MT MOONGLMATH_COMPLEX_MT

#define testmetatable moonglmath_testmetatable
#define checkmetatable moonglmath_checkmetatable

#define isvec moonglmath_isvec
#define testvec moonglmath_testvec
#define checkvec moonglmath_checkvec
#define pushvec moonglmath_pushvec

#define isbox moonglmath_isbox
#define testbox moonglmath_testbox
#define checkbox moonglmath_checkbox
#define pushbox moonglmath_pushbox

#define ismat moonglmath_ismat
#define testmat moonglmath_testmat
#define checkmat moonglmath_checkmat
#define pushmat moonglmath_pushmat

#define isquat moonglmath_isquat
#define testquat moonglmath_testquat
#define checkquat moonglmath_checkquat
#define pushquat moonglmath_pushquat

#define iscomplex moonglmath_iscomplex
#define testcomplex moonglmath_testcomplex
#define checkcomplex moonglmath_checkcomplex
#define pushcomplex moonglmath_pushcomplex

#define vec_clear moonglmath_vec_clear
#define vec_copy moonglmath_vec_copy
#define vec_unm moonglmath_vec_unm
#define vec_add moonglmath_vec_add
#define vec_sub moonglmath_vec_sub
#define vec_norm moonglmath_vec_norm
#define vec_norm2 moonglmath_vec_norm2
#define vec_normalize moonglmath_vec_normalize
#define vec_div moonglmath_vec_div
#define vec_dot moonglmath_vec_dot
#define vec_vxs moonglmath_vec_vxs
#define vec_vxv moonglmath_vec_vxv
#define vec_cross moonglmath_vec_cross
#define vec_clamp moonglmath_vec_clamp
#define vec_mix moonglmath_vec_mix
#define vec_step moonglmath_vec_step
#define vec_smoothstep moonglmath_vec_smoothstep
#define vec_fade moonglmath_vec_fade

#define box_clear moonglmath_box_clear
#define box_copy moonglmath_box_copy

#define mat_clear moonglmath_mat_clear
#define mat_copy moonglmath_mat_copy
#define mat_unm moonglmath_mat_unm
#define mat_transpose moonglmath_mat_transpose
#define mat_add moonglmath_mat_add
#define mat_sub moonglmath_mat_sub
#define mat_div moonglmath_mat_div
#define mat_mul moonglmath_mat_mul
#define mat_mulby moonglmath_mat_mulby
#define mat_mxs moonglmath_mat_mxs
#define mat_mxv moonglmath_mat_mxv
#define mat_vxm moonglmath_mat_vxm
#define mat_det2 moonglmath_mat_det2
#define mat_det3 moonglmath_mat_det3
#define mat_det4 moonglmath_mat_det4
#define mat_adj moonglmath_mat_adj
#define mat_inv moonglmath_mat_inv
#define mat_clamp moonglmath_mat_clamp
#define mat_mix moonglmath_mat_mix
#define mat_step moonglmath_mat_step
#define mat_smoothstep moonglmath_mat_smoothstep
#define mat_fade moonglmath_mat_fade

#define quat_clear moonglmath_quat_clear
#define quat_copy moonglmath_quat_copy
#define quat_unm moonglmath_quat_unm
#define quat_add moonglmath_quat_add
#define quat_sub moonglmath_quat_sub
#define quat_norm moonglmath_quat_norm
#define quat_norm2 moonglmath_quat_norm2
#define quat_normalize moonglmath_quat_normalize
#define quat_conj moonglmath_quat_conj
#define quat_inv moonglmath_quat_inv
#define quat_div moonglmath_quat_div
#define quat_mul moonglmath_quat_mul
#define quat_qxs moonglmath_quat_qxs
#define quat_mix moonglmath_quat_mix
#define quat_slerp moonglmath_quat_slerp

#define clamp moonglmath_clamp
#define mix moonglmath_mix
#define step moonglmath_step
#define smoothstep moonglmath_smoothstep
#define fade moonglmath_fade

#define now moonglmath_now

#define translate moonglmath_translate
#define scale moonglmath_scale
#define rotate_x moonglmath_rotate_x
#define rotate_y moonglmath_rotate_y
#define rotate_z moonglmath_rotate_z


#define look_at moonglmath_look_at
#define ortho moonglmath_ortho
#define frustum moonglmath_frustum
#define perspective moonglmath_perspective

#endif /* moonglmath_localDEFINED */



<|start_filename|>moonglmath/vecsugar.lua<|end_filename|>
-- The MIT License (MIT)
--
-- Copyright (c) 2016 <NAME>
--
-- Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--


-- 
-- Adds named-components access to MoonGLMATH vectors
-- ( v.x becomes an alias for v[1], v.y becomes an alias for v[2], and so on).
--
--
--
--

--local glmath = require("moonglmath")
--local mt = getmetatable(glmath.vec2())
do
local mt = getmetatable(moonglmath.vec2())
local methods = mt.__index

local rd = {} -- read functions
local wr = {} -- write indices

-- position components
rd.x = function(self) return self[1] end
rd.y = function(self) return self[2] end
rd.z = function(self) return self[3] end
rd.w = function(self) return self[4] end
wr.x, wr.y, wr.z, wr.w = 1,2,3,4

-- color components
rd.r = function(self) return self[1] end
rd.g = function(self) return self[2] end
rd.b = function(self) return self[3] end
rd.a = function(self) return self[4] end
wr.r, wr.g, wr.b, wr.a = 1,2,3,4

-- texture components
rd.s = function(self) return self[1] end
rd.t = function(self) return self[2] end
rd.p = function(self) return self[3] end
rd.q = function(self) return self[4] end
wr.s, wr.t, wr.p, wr.q = 1,2,3,4

mt.__index = function(self, key) 
	local f = rd[key]
	if f then return f(self) end
	return methods[key]
end

mt.__newindex = function(self, key, val)
	if type(key) == "number" or key == "size" or key == "type" then
		rawset(self, key, val)
		return
	end
	local i = wr[key]
	if i then 
		rawset(self, i, val)
	else
		error("cannot write field '" .. key .."'", 2)
	end
end

moonglmath.tovec2 = function(t) setmetatable(t, mt) t.type="column" t.size=2 return t end
moonglmath.tovec3 = function(t) setmetatable(t, mt) t.type="column" t.size=3 return t end
moonglmath.tovec4 = function(t) setmetatable(t, mt) t.type="column" t.size=4 return t end
moonglmath.tovec2r = function(t) setmetatable(t, mt) t.type="row" t.size=2 return t end
moonglmath.tovec3r = function(t) setmetatable(t, mt) t.type="row" t.size=3 return t end
moonglmath.tovec4r = function(t) setmetatable(t, mt) t.type="row" t.size=4 return t end

end


<|start_filename|>src/quat.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Check and push                                                               |
 *------------------------------------------------------------------------------*/

int testquat(lua_State *L, int arg, quat_t q)
/* Tests if the element at arg is a quaternion and sets q accordingly
 * (unless it is passed as 0).
 */
    {
    size_t i;
    if(!testmetatable(L, arg, QUAT_MT)) return 0;

    if(q != NULL)
        {
        for(i=0; i < 4; i++)
            {
            lua_geti(L, arg, i+1);
            q[i] = luaL_checknumber(L, -1);
            lua_pop(L, 1);
            }
        }
    return 1;
    }

int checkquat(lua_State *L, int arg, quat_t q)
/* Same as testquat(), but raises a error if the test fails.
 */
    {
    if(!testquat(L, arg, q))
        return luaL_argerror(L, arg, lua_pushfstring(L, "%s expected", QUAT_MT));
    return 1;
    }


int pushquat(lua_State *L, quat_t q)
    {
    size_t i;
    lua_newtable(L);
    setmetatable(L, QUAT_MT);
    for(i=0; i<4; i++)
        {
        lua_pushnumber(L, q[i]);
        lua_seti(L, -2, i+1);
        }
    return 1;
    }

/*------------------------------------------------------------------------------*
 | Vec                                                                          |
 *------------------------------------------------------------------------------*/

static int Quat(lua_State *L)
/* creates a quaternion from another quaternion, a scalar and a vec3, a matrix,
 * or a list of scalars.
 * the size is adapted by discarding exceeding values or adding zeros in lieu 
 * of missing values.
 * quat(q)
 * quat([w [, x [, y [, z]]])
 * quat(s, v)
 * quat(mat)
 * quat(axis, theta)
 */
    {
    quat_t q;
    vec_t v;
    double halftheta, s;
    size_t vsize, i, arg;

    if(testquat(L, 1, q))
        return pushquat(L, q);

    if(testvec(L, 2, v, &vsize, NULL))
        {
#if 0
        if(vsize != 3)
            return luaL_argerror(L, 2, "size 3 vector expected");
#endif
        q[0] = luaL_checknumber(L, 1);
        q[1] = v[0];
        q[2] = v[1];
        q[3] = v[2];
        return pushquat(L, q);
        }

    if(testvec(L, 1, v, &vsize, NULL)) // rotation quaternion
        {
        halftheta = luaL_checknumber(L, 2)/2;
        s = sin(halftheta);
        q[0] = cos(halftheta);
        q[1] = v[0] * s;
        q[2] = v[1] * s;
        q[3] = v[2] * s;
        quat_normalize(q);
        return pushquat(L, q);
        }

    if(testmat(L, 1, NULL, NULL, NULL))
        return quat_FromMat(L);

    arg = 1;
    for(i = 0; i < 4; i++)
        q[i] = luaL_optnumber(L, arg++, 0);
    return pushquat(L, q);
    }


static int IsQuat(lua_State *L)
    {
    if(!testquat(L, 1, NULL))
        lua_pushboolean(L, 0);
    else
        lua_pushboolean(L, 1);
    return 1;
    }
    
/*------------------------------------------------------------------------------*
 | ToString                                                                     |
 *------------------------------------------------------------------------------*/

static int ToString_(lua_State *L, quat_t q)
/* With snprintf because lua_pushfstring does not support the %g conversion specifier */
    {
#define SZ 512
#define space (SZ-p)
    char str[SZ];
    int p=0;
    p = snprintf(str, space, "< "FMT", "FMT", "FMT", "FMT" >", q[0], q[1], q[2], q[3]);
    lua_pushlstring(L, str, p);
    return 1;
#undef space
#undef SZ
    }

static int ToString(lua_State *L)
    {
    quat_t q;
    checkquat(L, 1, q);
    return ToString_(L, q);
    }


static int Concat(lua_State *L)
    {
    quat_t q;
    if(testquat(L, 1, q))
        {
        ToString_(L, q);
        lua_pushvalue(L, 2);
        }
    else if(testquat(L, 2, q))
        {
        lua_pushvalue(L, 1);
        ToString_(L, q);
        }
    else 
        return unexpected(L);
    lua_concat(L, 2);
    return 1;
    }


/*------------------------------------------------------------------------------*
 | Non-Lua functions (for internal use)                                         |
 *------------------------------------------------------------------------------*/

void quat_unm(quat_t dst, quat_t q)
    {
    size_t i; 
    quat_clear(dst);
    for(i=0; i < 4; i++)    
        dst[i] = -q[i];
    }
    
void quat_add(quat_t dst, quat_t q1, quat_t q2)
    {
    size_t i; 
    for(i=0; i < 4; i++)    
        dst[i] = q1[i] + q2[i];
    }
    
void quat_sub(quat_t dst, quat_t q1, quat_t q2)
    {
    size_t i; 
    for(i=0; i < 4; i++)    
        dst[i] = q1[i] - q2[i];
    }

double quat_norm(quat_t q)
    {
    size_t i;
    double r = 0;
    for(i=0; i < 4; i++)
        r += q[i]*q[i];
    return sqrt(r);
    }

double quat_norm2(quat_t q)
    {
    size_t i;
    double r = 0;
    for(i=0; i < 4; i++)
        r += q[i]*q[i];
    return r;
    }

void quat_normalize(quat_t q) 
/* in place */
    {
    size_t i;
    double norm = quat_norm(q);
    for(i=0; i < 4; i++)    
        q[i] = q[i]/norm;
    }
        
void quat_conj(quat_t dst, quat_t q) 
    {
    dst[0] = q[0];
    dst[1] = -q[1];
    dst[2] = -q[2];
    dst[3] = -q[3];
    }


void quat_inv(quat_t dst, quat_t q) 
    {
    double norm2 = quat_norm(q);
    norm2 = norm2*norm2;
    dst[0] = q[0]/norm2;
    dst[1] = -q[1]/norm2;
    dst[2] = -q[2]/norm2;
    dst[3] = -q[3]/norm2;
    }

void quat_div(quat_t dst, quat_t q, double s)
    {
    size_t i; 
    for(i=0; i < 4; i++)    
        dst[i] = q[i] / s;
    }

void quat_mul(quat_t dst, quat_t q, quat_t p)
    {
    dst[0] = q[0]*p[0] - q[1]*p[1] - q[2]*p[2] - q[3]*p[3];
    dst[1] = q[0]*p[1] + q[1]*p[0] + q[2]*p[3] - q[3]*p[2];
    dst[2] = q[0]*p[2] + q[2]*p[0] + q[3]*p[1] - q[1]*p[3];
    dst[3] = q[0]*p[3] + q[3]*p[0] + q[1]*p[2] - q[2]*p[1];
    }

static void quat_mulby(quat_t dst, quat_t p) /* in place, dst = dst * q */
    {
    quat_t q;
    quat_copy(q, dst);  
    dst[0] = q[0]*p[0] - q[1]*p[1] - q[2]*p[2] - q[3]*p[3];
    dst[1] = q[0]*p[1] + q[1]*p[0] + q[2]*p[3] - q[3]*p[2];
    dst[2] = q[0]*p[2] + q[2]*p[0] + q[3]*p[1] - q[1]*p[3];
    dst[3] = q[0]*p[3] + q[3]*p[0] + q[1]*p[2] - q[2]*p[1];
    }


void quat_qxs(quat_t dst, quat_t q, double s)
    {
    size_t i; 
    for(i=0; i < 4; i++)    
        dst[i] = q[i] * s;
    }

void quat_mix(quat_t dst, quat_t q, quat_t p, double t)
    {
    double t1 = 1.0f - t;
    dst[0] = t1*q[0] + t*p[0];
    dst[1] = t1*q[1] + t*p[1];
    dst[2] = t1*q[2] + t*p[2];
    dst[3] = t1*q[3] + t*p[3];
    }

void quat_slerp(quat_t dst, quat_t q, quat_t p, double t)
/* Rfr: "3D Math Primer for Graphics and Game Development", by <NAME>, <NAME>,
 *      AK Peters/CRC Press, section 8.5.11.
 */
    {
    double c, s, theta, t0, t1;
    c = q[0]*p[0] + q[1]*p[1] + q[2]*p[2] + q[3]*p[3];
    if(c < 0.0f)
        {
        c = -c;
        p[0] = - p[0];
        p[1] = - p[1];
        p[2] = - p[2];
        p[3] = - p[3];
        }
    if(c > .9999f) // q and p are very close: use linear interpolation
        quat_mix(dst, q, p, t);
    else
        {
        s = sqrt(1.0f - c*c);
        theta = atan2(s, c);
        t0 = sin((1.0f - t)*theta)/s;
        t1 = sin(t*theta)/s;
        dst[0] = t0*q[0] + t1*p[0];
        dst[1] = t0*q[1] + t1*p[1];
        dst[2] = t0*q[2] + t1*p[2];
        dst[3] = t0*q[3] + t1*p[3];
        }
    }

/*------------------------------------------------------------------------------*
 | Metamethods                                                                  |
 *------------------------------------------------------------------------------*/

static int Unm(lua_State *L)
    {
    quat_t q; 
    size_t i; 
    checkquat(L, 1, q);
    for(i=0; i < 4; i++)    
        q[i] = -q[i];
    return pushquat(L, q);
    }


static int Add(lua_State *L)
    {
    quat_t q, q1; 
    size_t i; 
    checkquat(L, 1, q);
    checkquat(L, 2, q1);
    for(i=0; i < 4; i++)    
        q[i] += q1[i];
    return pushquat(L, q);
    }

static int Sub(lua_State *L)
    {
    quat_t q, q1; 
    size_t i; 
    checkquat(L, 1, q);
    checkquat(L, 2, q1);
    for(i=0; i < 4; i++)    
        q[i] -= q1[i];
    return pushquat(L, q);
    }

static int Qxs(lua_State *L, int sarg, int qarg)
    {
    quat_t q; 
    size_t i; 
    double s = luaL_checknumber(L, sarg);
    checkquat(L, qarg, q);
    for(i=0; i < 4; i++)    
        q[i] *= s;
    return pushquat(L, q);
    }

static int Mul(lua_State *L)
    {
    quat_t q, p, r; 
    if(lua_isnumber(L, 1))
        return Qxs(L, 1, 2);
    if(lua_isnumber(L, 2))
        return Qxs(L, 2, 1);
    checkquat(L, 1, q);
    checkquat(L, 2, p);
    r[0] = q[0]*p[0] - q[1]*p[1] - q[2]*p[2] - q[3]*p[3];
    r[1] = q[0]*p[1] + q[1]*p[0] + q[2]*p[3] - q[3]*p[2];
    r[2] = q[0]*p[2] + q[2]*p[0] + q[3]*p[1] - q[1]*p[3];
    r[3] = q[0]*p[3] + q[3]*p[0] + q[1]*p[2] - q[2]*p[1];
    return pushquat(L, r);
    }

static int Pow(lua_State *L)
    {
    quat_t q, dst; 
    lua_Integer n, i;
    checkquat(L, 1, q);
    n = luaL_checkinteger(L, 2);
    if(n == 0)
        {
        quat_clear(dst); dst[0]=1;  
        }
    else
        {
        if(n > 0)
            quat_copy(dst, q);
        else
            {
            quat_inv(dst, q);
            quat_copy(q, dst);
            n = -n;
            }
        for(i = 0; i < (n-1); i++)
            quat_mulby(dst, q);
        }
    return pushquat(L, dst);
    }


static int Div(lua_State *L)
    {
    quat_t q; 
    size_t i; 
    double s;
    checkquat(L, 1, q);
    s = luaL_checknumber(L, 2);
    for(i=0; i < 4; i++)    
        q[i] /= s;
    return pushquat(L, q);
    }

int quat_Norm(lua_State *L)
    {
    quat_t q;
    size_t i;
    double r = 0;
    checkquat(L, 1, q);
    for(i=0; i < 4; i++)
        r += q[i]*q[i];
    lua_pushnumber(L, sqrt(r));
    return 1;
    }

int quat_Norm2(lua_State *L)
    {
    quat_t q;
    size_t i;
    double r = 0;
    checkquat(L, 1, q);
    for(i=0; i < 4; i++)
        r += q[i]*q[i];
    lua_pushnumber(L, r);
    return 1;
    }

int quat_Conj(lua_State *L)
    {
    quat_t q; 
    checkquat(L, 1, q);
    q[1] = -q[1];
    q[2] = -q[2];
    q[3] = -q[3];
    return pushquat(L, q);
    }

int quat_Normalize(lua_State *L)
    {
    quat_t q; 
    checkquat(L, 1, q);
    quat_normalize(q);
    return pushquat(L, q);
    }

int quat_Inv(lua_State *L)
    {
    quat_t q, inv;
    checkquat(L, 1, q);
    quat_inv(inv, q);
    return pushquat(L, inv);
    }

int quat_Parts(lua_State *L)
    {
    quat_t q; 
    vec_t v;
    checkquat(L, 1, q);
    v[0] = q[1];
    v[1] = q[2];
    v[2] = q[3];
    lua_pushnumber(L, q[0]);
    pushvec(L, v, 3, 3, 0);
    return 2;
    }

/*--------------------------------------------------------------------------*
 | quaternion <-> rotation matrix conversion                                |
 *--------------------------------------------------------------------------*/
/* Rfr: https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion */

static int quat_Mat(lua_State *L, size_t n)
/* returns the rotation matrix corresponding to the quaternion */
    {
#define w q[0]
#define x q[1]
#define y q[2]
#define z q[3]
    quat_t q; 
    mat_t m;
    double s, wx, wy, wz, xx, yy, zz, xy, xz, yz;
    checkquat(L, 1, q);
    mat_clear(m);
    s = w*w + x*x + y*y +z*z;
    if(s == 0)
        {
        m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1;
        return pushmat(L, m, 4, 4, n, n);
        }
    s = 2 / s;  
    wx = s*w*x;
    wy = s*w*y;
    wz = s*w*z;
    xx = s*x*x;
    yy = s*y*y;
    zz = s*z*z;
    xy = s*x*y;
    xz = s*x*z;
    yz = s*y*z;
    
    m[0][0] = 1 - yy - zz;
    m[1][1] = 1 - xx - zz;
    m[2][2] = 1 - xx - yy;
    m[3][3] = 1;
    m[0][1] = xy - wz;
    m[1][0] = xy + wz;
    m[0][2] = xz + wy;
    m[2][0] = xz - wy;
    m[1][2] = yz - wx;
    m[2][1] = yz + wx;
    return pushmat(L, m, 4, 4, n, n);
#undef w
#undef x
#undef y
#undef z
    }

static int quat_Mat3(lua_State *L)
    { return quat_Mat(L, 3); }

static int quat_Mat4(lua_State *L)
    { return quat_Mat(L, 4); }


int quat_FromMat(lua_State *L)
    {
    size_t nr, nc;
    double t, s, r;
    mat_t m;
    quat_t q;
    checkmat(L, 1, m, &nr, &nc);
    if( !(((nr==3) && (nc==3)) || ((nr==4) && (nc==4))) )
        return luaL_argerror(L, 1, "expected 3x3 or 4x4 matrix");
    t = m[0][0] + m[1][1] + m[2][2];
    if( t < 0 )
        {
        r = sqrt(1 + m[0][0] - m[1][1] - m[2][2]);
        s = 0.5/r;
        q[0] = (m[2][1] - m[1][2])*s;
        q[1] = 0.5*r;
        q[2] = (m[0][1] + m[1][0])*s;
        q[3] = (m[2][0] + m[0][2])*s;
        }
    else
        {
        r = sqrt(1+t);
        s = 0.5/r;
        q[0] = 0.5*r;
        q[1] = (m[2][1] - m[1][2])*s;
        q[2] = (m[0][2] - m[2][0])*s;
        q[3] = (m[1][0] + m[0][1])*s;
        }
    return pushquat(L, q);
    }


int quat_Mix(lua_State *L)
    {
    quat_t dst, q, p;
    double t;
    checkquat(L, 1, q);
    checkquat(L, 2, p);
    t = luaL_checknumber(L, 3);
    quat_mix(dst, q, p, t);
    return pushquat(L, dst);
    }

int quat_Slerp(lua_State *L)
    {
    quat_t dst, q, p;
    double t;
    checkquat(L, 1, q);
    checkquat(L, 2, p);
    t = luaL_checknumber(L, 3);
    quat_slerp(dst, q, p, t);
    return pushquat(L, dst);
    }


//@@ TODO rotate()
//@@ TODO quaternion <-> Euler

static const struct luaL_Reg Metamethods[] = 
    {
        { "__tostring", ToString },
        { "__concat", Concat },
        { "__unm", Unm },
        { "__add", Add },
        { "__sub", Sub },
        { "__mul", Mul },
        { "__div", Div },
        { "__pow", Pow },
        { NULL, NULL } /* sentinel */
    };

static const struct luaL_Reg Methods[] = 
    {
        { "parts", quat_Parts },
        { "conj", quat_Conj },
        { "norm", quat_Norm },
        { "norm2", quat_Norm2 },
        { "normalize", quat_Normalize },
        { "inv", quat_Inv },
        { "mat3", quat_Mat3 },
        { "mat4", quat_Mat4 },
        { "mix", quat_Mix },
        { "slerp", quat_Slerp },
        { NULL, NULL } /* sentinel */
    };


/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "quat", Quat },
        { "isquat", IsQuat },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_quat(lua_State *L)
    {
    newmetatable(L, QUAT_MT);
    metatable_setfuncs(L, QUAT_MT, Metamethods, Methods);
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>doc/index.html<|end_filename|>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.5">
<meta name="author" content="<NAME>">
<title>MoonGLMATH Reference Manual</title>
<style>
/*! normalize.css v2.1.2 | MIT License | git.io/normalize */
/* ========================================================================== HTML5 display definitions ========================================================================== */
/** Correct `block` display not defined in IE 8/9. */
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; }

/** Correct `inline-block` display not defined in IE 8/9. */
audio, canvas, video { display: inline-block; }

/** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */
audio:not([controls]) { display: none; height: 0; }

/** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */
[hidden], template { display: none; }

script { display: none !important; }

/* ========================================================================== Base ========================================================================== */
/** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */
html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ }

/** Remove default margin. */
body { margin: 0; }

/* ========================================================================== Links ========================================================================== */
/** Remove the gray background color from active links in IE 10. */
a { background: transparent; }

/** Address `outline` inconsistency between Chrome and other browsers. */
a:focus { outline: thin dotted; }

/** Improve readability when focused and also mouse hovered in all browsers. */
a:active, a:hover { outline: 0; }

/* ========================================================================== Typography ========================================================================== */
/** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */
h1 { font-size: 2em; margin: 0.67em 0; }

/** Address styling not present in IE 8/9, Safari 5, and Chrome. */
abbr[title] { border-bottom: 1px dotted; }

/** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */
b, strong { font-weight: bold; }

/** Address styling not present in Safari 5 and Chrome. */
dfn { font-style: italic; }

/** Address differences between Firefox and other browsers. */
hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; }

/** Address styling not present in IE 8/9. */
mark { background: #ff0; color: #000; }

/** Correct font family set oddly in Safari 5 and Chrome. */
code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; }

/** Improve readability of pre-formatted text in all browsers. */
pre { white-space: pre-wrap; }

/** Set consistent quote types. */
q { quotes: "\201C" "\201D" "\2018" "\2019"; }

/** Address inconsistent and variable font size in all browsers. */
small { font-size: 80%; }

/** Prevent `sub` and `sup` affecting `line-height` in all browsers. */
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }

sup { top: -0.5em; }

sub { bottom: -0.25em; }

/* ========================================================================== Embedded content ========================================================================== */
/** Remove border when inside `a` element in IE 8/9. */
img { border: 0; }

/** Correct overflow displayed oddly in IE 9. */
svg:not(:root) { overflow: hidden; }

/* ========================================================================== Figures ========================================================================== */
/** Address margin not present in IE 8/9 and Safari 5. */
figure { margin: 0; }

/* ========================================================================== Forms ========================================================================== */
/** Define consistent border, margin, and padding. */
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }

/** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */
legend { border: 0; /* 1 */ padding: 0; /* 2 */ }

/** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */
button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ }

/** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
button, input { line-height: normal; }

/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */
button, select { text-transform: none; }

/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */
button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ }

/** Re-set default cursor for disabled elements. */
button[disabled], html input[disabled] { cursor: default; }

/** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ }

/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; }

/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }

/** Remove inner padding and border in Firefox 4+. */
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }

/** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */
textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ }

/* ========================================================================== Tables ========================================================================== */
/** Remove most spacing between table cells. */
table { border-collapse: collapse; border-spacing: 0; }

meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; }

meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; }

meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; }

*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }

html, body { font-size: 100%; }

body { background: white; color: #222222; padding: 0; margin: 0; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; }

a:hover { cursor: pointer; }

img, object, embed { max-width: 100%; height: auto; }

object, embed { height: 100%; }

img { -ms-interpolation-mode: bicubic; }

#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; }

.left { float: left !important; }

.right { float: right !important; }

.text-left { text-align: left !important; }

.text-right { text-align: right !important; }

.text-center { text-align: center !important; }

.text-justify { text-align: justify !important; }

.hide { display: none; }

.antialiased, body { -webkit-font-smoothing: antialiased; }

img { display: inline-block; vertical-align: middle; }

textarea { height: auto; min-height: 50px; }

select { width: 100%; }

p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; }

.subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { line-height: 1.4; color: #003b6b; font-weight: 300; margin-top: 0.2em; margin-bottom: 0.5em; }

/* Typography resets */
div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; }

/* Default Link Styles */
a { color: #00579e; text-decoration: none; line-height: inherit; }
a:hover, a:focus { color: #333333; }
a img { border: none; }

/* Default paragraph styles */
p { font-family: Arial, sans-serif; font-weight: normal; font-size: 1em; line-height: 1.6; margin-bottom: 0.75em; text-rendering: optimizeLegibility; }
p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; }

/* Default header styles */
h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: Arial, sans-serif; font-weight: normal; font-style: normal; color: #7b2d00; text-rendering: optimizeLegibility; margin-top: 0.5em; margin-bottom: 0.5em; line-height: 1.2125em; }
h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: #ff6b15; line-height: 0; }

h1 { font-size: 2.125em; }

h2 { font-size: 1.6875em; }

h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; }

h4 { font-size: 1.125em; }

h5 { font-size: 1.125em; }

h6 { font-size: 1em; }

hr { border: solid #dddddd; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; }

/* Helpful Typography Defaults */
em, i { font-style: italic; line-height: inherit; }

strong, b { font-weight: bold; line-height: inherit; }

small { font-size: 60%; line-height: inherit; }

code { font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: bold; color: #003426; }

/* Lists */
ul, ol, dl { font-size: 1em; line-height: 1.6; margin-bottom: 0.75em; list-style-position: outside; font-family: Arial, sans-serif; }

ul, ol { margin-left: 1.5em; }
ul.no-bullet, ol.no-bullet { margin-left: 1.5em; }

/* Unordered Lists */
ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ }
ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; }
ul.square { list-style-type: square; }
ul.circle { list-style-type: circle; }
ul.disc { list-style-type: disc; }
ul.no-bullet { list-style: none; }

/* Ordered Lists */
ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; }

/* Definition Lists */
dl dt { margin-bottom: 0.3em; font-weight: bold; }
dl dd { margin-bottom: 0.75em; }

/* Abbreviations */
abbr, acronym { text-transform: uppercase; font-size: 90%; color: black; border-bottom: 1px dotted #dddddd; cursor: help; }

abbr { text-transform: none; }

/* Blockquotes */
blockquote { margin: 0 0 0.75em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; }
blockquote cite { display: block; font-size: 0.8125em; color: #e15200; }
blockquote cite:before { content: "\2014 \0020"; }
blockquote cite a, blockquote cite a:visited { color: #e15200; }

blockquote, blockquote p { line-height: 1.6; color: #333333; }

/* Microformats */
.vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; }
.vcard li { margin: 0; display: block; }
.vcard .fn { font-weight: bold; font-size: 0.9375em; }

.vevent .summary { font-weight: bold; }
.vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; }

@media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; }
  h1 { font-size: 2.75em; }
  h2 { font-size: 2.3125em; }
  h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; }
  h4 { font-size: 1.4375em; } }
/* Tables */
table { background: white; margin-bottom: 1.25em; border: solid 1px #d8d8ce; }
table thead, table tfoot { background: -webkit-linear-gradient(top, #add386, #90b66a); font-weight: bold; }
table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: white; text-align: left; }
table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: #6d6e71; }
table tr.even, table tr.alt, table tr:nth-of-type(even) { background: #edf2f2; }
table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.4; }

h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; }

a:hover, a:focus { text-decoration: underline; }

.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; }
.clearfix:after, .float-group:after { clear: both; }

*:not(pre) > code { font-size: inherit; font-style: normal !important; letter-spacing: 0; padding: 3px 2px 1px 2px; background-color: #eeeeee; border: 1px solid #dddddd; -webkit-border-radius: 0; border-radius: 0; line-height: inherit; }

pre, pre > code { line-height: 1.6; color: black; font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: normal; }

.keyseq { color: #333333; }

kbd { display: inline-block; color: black; font-size: 0.75em; line-height: 1.4; background-color: #f7f7f7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; margin: -0.15em 0.15em 0 0.15em; padding: 0.2em 0.6em 0.2em 0.5em; vertical-align: middle; white-space: nowrap; }

.keyseq kbd:first-child { margin-left: 0; }

.keyseq kbd:last-child { margin-right: 0; }

.menuseq, .menu { color: black; }

b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; }

b.button:before { content: "["; padding: 0 3px 0 2px; }

b.button:after { content: "]"; padding: 0 2px 0 3px; }

#header, #content, #footnotes, #footer { width: 100%; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: 0; max-width: 62.5em; *zoom: 1; position: relative; padding-left: 1.5em; padding-right: 1.5em; }
#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; }
#header:after, #content:after, #footnotes:after, #footer:after { clear: both; }

#content { margin-top: 1.25em; }

#content:before { content: none; }

#header > h1:first-child { color: #7b2d00; margin-top: 2.25rem; margin-bottom: 0; }
#header > h1:first-child + #toc { margin-top: 8px; border-top: 1px solid #dddddd; }
#header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { border-bottom: 1px solid #dddddd; padding-bottom: 8px; }
#header .details { border-bottom: 1px solid #dddddd; line-height: 1.45; padding-top: 0.25em; padding-bottom: 0.25em; padding-left: 0.25em; color: #e15200; display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; }
#header .details span:first-child { margin-left: -0.125em; }
#header .details span.email a { color: #333333; }
#header .details br { display: none; }
#header .details br + span:before { content: "\00a0\2013\00a0"; }
#header .details br + span.author:before { content: "\00a0\22c5\00a0"; color: #333333; }
#header .details br + span#revremark:before { content: "\00a0|\00a0"; }
#header #revnumber { text-transform: capitalize; }
#header #revnumber:after { content: "\00a0"; }

#content > h1:first-child:not([class]) { color: #7b2d00; border-bottom: 1px solid #dddddd; padding-bottom: 8px; margin-top: 0; padding-top: 1rem; margin-bottom: 1.25rem; }

#toc { border-bottom: 0 solid #dddddd; padding-bottom: 0.5em; }
#toc > ul { margin-left: 0.125em; }
#toc ul.sectlevel0 > li > a { font-style: italic; }
#toc ul.sectlevel0 ul.sectlevel1 { margin: 0.5em 0; }
#toc ul { font-family: Arial, sans-serif; list-style-type: none; }
#toc a { text-decoration: none; }
#toc a:active { text-decoration: underline; }

#toctitle { color: #003b6b; font-size: 1.2em; }

@media only screen and (min-width: 768px) { #toctitle { font-size: 1.375em; }
  body.toc2 { padding-left: 15em; padding-right: 0; }
  #toc.toc2 { margin-top: 0 !important; background-color: white; position: fixed; width: 15em; left: 0; top: 0; border-right: 1px solid #dddddd; border-top-width: 0 !important; border-bottom-width: 0 !important; z-index: 1000; padding: 1.25em 1em; height: 100%; overflow: auto; }
  #toc.toc2 #toctitle { margin-top: 0; font-size: 1.2em; }
  #toc.toc2 > ul { font-size: 0.9em; margin-bottom: 0; }
  #toc.toc2 ul ul { margin-left: 0; padding-left: 1em; }
  #toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
  body.toc2.toc-right { padding-left: 0; padding-right: 15em; }
  body.toc2.toc-right #toc.toc2 { border-right-width: 0; border-left: 1px solid #dddddd; left: auto; right: 0; } }
@media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; padding-right: 0; }
  #toc.toc2 { width: 20em; }
  #toc.toc2 #toctitle { font-size: 1.375em; }
  #toc.toc2 > ul { font-size: 0.95em; }
  #toc.toc2 ul ul { padding-left: 1.25em; }
  body.toc2.toc-right { padding-left: 0; padding-right: 20em; } }
#content #toc { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 0; border-radius: 0; }
#content #toc > :first-child { margin-top: 0; }
#content #toc > :last-child { margin-bottom: 0; }

#footer { max-width: 100%; background-color: none; padding: 1.25em; }

#footer-text { color: black; line-height: 1.44; }

.sect1 { padding-bottom: 0.625em; }

@media only screen and (min-width: 768px) { .sect1 { padding-bottom: 1.25em; } }
.sect1 + .sect1 { border-top: 0 solid #dddddd; }

#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; z-index: 1001; width: 1.5ex; margin-left: -1.5ex; display: block; text-decoration: none !important; visibility: hidden; text-align: center; font-weight: normal; }
#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: "\00A7"; font-size: 0.85em; display: block; padding-top: 0.1em; }
#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; }
#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #7b2d00; text-decoration: none; }
#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #622400; }

.audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { margin-bottom: 1.25em; }

.admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-rendering: optimizeLegibility; text-align: left; }

table.tableblock > caption.title { white-space: nowrap; overflow: visible; max-width: 0; }

.paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { color: #7b2d00; }

table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; }

.admonitionblock > table { border-collapse: separate; border: 0; background: none; width: 100%; }
.admonitionblock > table td.icon { text-align: center; width: 80px; }
.admonitionblock > table td.icon img { max-width: none; }
.admonitionblock > table td.icon .title { font-weight: bold; font-family: Arial, sans-serif; text-transform: uppercase; }
.admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #dddddd; color: #e15200; }
.admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; }

.exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 0; border-radius: 0; }
.exampleblock > .content > :first-child { margin-top: 0; }
.exampleblock > .content > :last-child { margin-bottom: 0; }

.sidebarblock { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: white; -webkit-border-radius: 0; border-radius: 0; }
.sidebarblock > :first-child { margin-top: 0; }
.sidebarblock > :last-child { margin-bottom: 0; }
.sidebarblock > .content > .title { color: #003b6b; margin-top: 0; }

.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; }

.literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { background: #eeeeee; }
.sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { background: #f2f1f1; }

.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { border: 1px dashed #666666; -webkit-border-radius: 0; border-radius: 0; word-wrap: break-word; padding: 1.25em 1.5625em 1.125em 1.5625em; font-size: 0.8125em; }
.literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; }
@media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.90625em; } }
@media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 1em; } }

.literalblock.output pre { color: #eeeeee; background-color: black; }

.listingblock pre.highlightjs { padding: 0; }
.listingblock pre.highlightjs > code { padding: 1.25em 1.5625em 1.125em 1.5625em; -webkit-border-radius: 0; border-radius: 0; }

.listingblock > .content { position: relative; }

.listingblock code[data-lang]:before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; right: 0.5rem; line-height: 1; text-transform: uppercase; color: #999; }

.listingblock:hover code[data-lang]:before { display: block; }

.listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; }

.listingblock.terminal pre .command:not([data-prompt]):before { content: "$"; }

table.pyhltable { border-collapse: separate; border: 0; margin-bottom: 0; background: none; }

table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; }

table.pyhltable td.code { padding-left: .75em; padding-right: 0; }

pre.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #dddddd; }

pre.pygments .lineno { display: inline-block; margin-right: .25em; }

table.pyhltable .linenodiv { background: none !important; padding-right: 0 !important; }

.quoteblock { margin: 0 1em 0.75em 1.5em; display: table; }
.quoteblock > .title { margin-left: -1.5em; margin-bottom: 0.75em; }
.quoteblock blockquote, .quoteblock blockquote p { color: #333333; font-size: 1.15rem; line-height: 1.75; word-spacing: 0.1em; letter-spacing: 0; font-style: italic; text-align: justify; }
.quoteblock blockquote { margin: 0; padding: 0; border: 0; }
.quoteblock blockquote:before { content: "\201c"; float: left; font-size: 2.75em; font-weight: bold; line-height: 0.6em; margin-left: -0.6em; color: #003b6b; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); }
.quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; }
.quoteblock .attribution { margin-top: 0.5em; margin-right: 0.5ex; text-align: right; }
.quoteblock .quoteblock { margin-left: 0; margin-right: 0; padding: 0.5em 0; border-left: 3px solid #e15200; }
.quoteblock .quoteblock blockquote { padding: 0 0 0 0.75em; }
.quoteblock .quoteblock blockquote:before { display: none; }

.verseblock { margin: 0 1em 0.75em 1em; }
.verseblock pre { font-family: "Open Sans", "DejaVu Sans", sans; font-size: 1.15rem; color: #333333; font-weight: 300; text-rendering: optimizeLegibility; }
.verseblock pre strong { font-weight: 400; }
.verseblock .attribution { margin-top: 1.25rem; margin-left: 0.5ex; }

.quoteblock .attribution, .verseblock .attribution { font-size: 0.8125em; line-height: 1.45; font-style: italic; }
.quoteblock .attribution br, .verseblock .attribution br { display: none; }
.quoteblock .attribution cite, .verseblock .attribution cite { display: block; letter-spacing: -0.05em; color: #e15200; }

.quoteblock.abstract { margin: 0 0 0.75em 0; display: block; }
.quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { text-align: left; word-spacing: 0; }
.quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { display: none; }

table.tableblock { max-width: 100%; border-collapse: separate; }
table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { margin-bottom: 0; }

table.spread { width: 100%; }

table.tableblock, th.tableblock, td.tableblock { border: 0 solid #d8d8ce; }

table.grid-all th.tableblock, table.grid-all td.tableblock { border-width: 0 1px 1px 0; }

table.grid-all tfoot > tr > th.tableblock, table.grid-all tfoot > tr > td.tableblock { border-width: 1px 1px 0 0; }

table.grid-cols th.tableblock, table.grid-cols td.tableblock { border-width: 0 1px 0 0; }

table.grid-all * > tr > .tableblock:last-child, table.grid-cols * > tr > .tableblock:last-child { border-right-width: 0; }

table.grid-rows th.tableblock, table.grid-rows td.tableblock { border-width: 0 0 1px 0; }

table.grid-all tbody > tr:last-child > th.tableblock, table.grid-all tbody > tr:last-child > td.tableblock, table.grid-all thead:last-child > tr > th.tableblock, table.grid-rows tbody > tr:last-child > th.tableblock, table.grid-rows tbody > tr:last-child > td.tableblock, table.grid-rows thead:last-child > tr > th.tableblock { border-bottom-width: 0; }

table.grid-rows tfoot > tr > th.tableblock, table.grid-rows tfoot > tr > td.tableblock { border-width: 1px 0 0 0; }

table.frame-all { border-width: 1px; }

table.frame-sides { border-width: 0 1px; }

table.frame-topbot { border-width: 1px 0; }

th.halign-left, td.halign-left { text-align: left; }

th.halign-right, td.halign-right { text-align: right; }

th.halign-center, td.halign-center { text-align: center; }

th.valign-top, td.valign-top { vertical-align: top; }

th.valign-bottom, td.valign-bottom { vertical-align: bottom; }

th.valign-middle, td.valign-middle { vertical-align: middle; }

table thead th, table tfoot th { font-weight: bold; }

tbody tr th { display: table-cell; line-height: 1.4; background: -webkit-linear-gradient(top, #add386, #90b66a); }

tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: white; font-weight: bold; }

p.tableblock > code:only-child { background: none; padding: 0; }

p.tableblock { font-size: 1em; }

td > div.verse { white-space: pre; }

ol { margin-left: 1.75em; }

ul li ol { margin-left: 1.5em; }

dl dd { margin-left: 1.125em; }

dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; }

ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.375em; }

ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; }

ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; }

ul.checklist li > p:first-child > .fa-square-o:first-child, ul.checklist li > p:first-child > .fa-check-square-o:first-child { width: 1em; font-size: 0.85em; }

ul.checklist li > p:first-child > input[type="checkbox"]:first-child { width: 1em; position: relative; top: 1px; }

ul.inline { margin: 0 auto 0.375em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; }
ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; }
ul.inline > li > * { display: block; }

.unstyled dl dt { font-weight: normal; font-style: normal; }

ol.arabic { list-style-type: decimal; }

ol.decimal { list-style-type: decimal-leading-zero; }

ol.loweralpha { list-style-type: lower-alpha; }

ol.upperalpha { list-style-type: upper-alpha; }

ol.lowerroman { list-style-type: lower-roman; }

ol.upperroman { list-style-type: upper-roman; }

ol.lowergreek { list-style-type: lower-greek; }

.hdlist > table, .colist > table { border: 0; background: none; }
.hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; }

td.hdlist1 { padding-right: .75em; font-weight: bold; }

td.hdlist1, td.hdlist2 { vertical-align: top; }

.literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; }

.colist > table tr > td:first-of-type { padding: 0 0.75em; line-height: 1; }
.colist > table tr > td:last-of-type { padding: 0.25em 0; }

.thumb, .th { line-height: 0; display: inline-block; border: solid 4px white; -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; }

.imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; }
.imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; }
.imageblock > .title { margin-bottom: 0; }
.imageblock.thumb, .imageblock.th { border-width: 6px; }
.imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; }

.image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; }
.image.left { margin-right: 0.625em; }
.image.right { margin-left: 0.625em; }

a.image { text-decoration: none; }

span.footnote, span.footnoteref { vertical-align: super; font-size: 0.875em; }
span.footnote a, span.footnoteref a { text-decoration: none; }
span.footnote a:active, span.footnoteref a:active { text-decoration: underline; }

#footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; }
#footnotes hr { width: 20%; min-width: 6.25em; margin: -.25em 0 .75em 0; border-width: 1px 0 0 0; }
#footnotes .footnote { padding: 0 0.375em; line-height: 1.3; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.2em; margin-bottom: .2em; }
#footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; }
#footnotes .footnote:last-of-type { margin-bottom: 0; }

#content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; }

.gist .file-data > table { border: 0; background: #fff; width: 100%; margin-bottom: 0; }
.gist .file-data > table td.line-data { width: 99%; }

div.unbreakable { page-break-inside: avoid; }

.big { font-size: larger; }

.small { font-size: smaller; }

.underline { text-decoration: underline; }

.overline { text-decoration: overline; }

.line-through { text-decoration: line-through; }

.aqua { color: #00bfbf; }

.aqua-background { background-color: #00fafa; }

.black { color: black; }

.black-background { background-color: black; }

.blue { color: #0000bf; }

.blue-background { background-color: #0000fa; }

.fuchsia { color: #bf00bf; }

.fuchsia-background { background-color: #fa00fa; }

.gray { color: #606060; }

.gray-background { background-color: #7d7d7d; }

.green { color: #006000; }

.green-background { background-color: #007d00; }

.lime { color: #00bf00; }

.lime-background { background-color: #00fa00; }

.maroon { color: #600000; }

.maroon-background { background-color: #7d0000; }

.navy { color: #000060; }

.navy-background { background-color: #00007d; }

.olive { color: #606000; }

.olive-background { background-color: #7d7d00; }

.purple { color: #600060; }

.purple-background { background-color: #7d007d; }

.red { color: #bf0000; }

.red-background { background-color: #fa0000; }

.silver { color: #909090; }

.silver-background { background-color: #bcbcbc; }

.teal { color: #006060; }

.teal-background { background-color: #007d7d; }

.white { color: #bfbfbf; }

.white-background { background-color: #fafafa; }

.yellow { color: #bfbf00; }

.yellow-background { background-color: #fafa00; }

span.icon > .fa { cursor: default; }

.admonitionblock td.icon [class^="fa icon-"] { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; }
.admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #004176; }
.admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; }
.admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; }
.admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; }
.admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; }

.conum[data-value] { display: inline-block; color: #fff !important; background-color: black; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; font-size: 0.75em; width: 1.67em; height: 1.67em; line-height: 1.67em; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-style: normal; font-weight: bold; }
.conum[data-value] * { color: #fff !important; }
.conum[data-value] + b { display: none; }
.conum[data-value]:after { content: attr(data-value); }
pre .conum[data-value] { position: relative; top: -0.125em; }

b.conum * { color: inherit !important; }

.conum:not([data-value]):empty { display: none; }

h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { border-bottom: 1px solid #dddddd; }

.sect1 { padding-bottom: 0; }

#toctitle { color: #00406F; font-weight: normal; margin-top: 1.5em; }

.sidebarblock { border-color: #aaa; }

code { -webkit-border-radius: 4px; border-radius: 4px; }

p.tableblock.header { color: #6d6e71; }

.literalblock pre, .listingblock pre { background: #eeeeee; }

</style>
<style>
.listingblock .pygments .hll { background-color: #ffffcc }
.listingblock .pygments, .listingblock .pygments code { background: #ffffff; }
.listingblock .pygments .tok-c { color: #aaaaaa; font-style: italic } /* Comment */
.listingblock .pygments .tok-err { color: #FF0000; background-color: #FFAAAA } /* Error */
.listingblock .pygments .tok-k { color: #0000aa } /* Keyword */
.listingblock .pygments .tok-ch { color: #aaaaaa; font-style: italic } /* Comment.Hashbang */
.listingblock .pygments .tok-cm { color: #aaaaaa; font-style: italic } /* Comment.Multiline */
.listingblock .pygments .tok-cp { color: #4c8317 } /* Comment.Preproc */
.listingblock .pygments .tok-cpf { color: #aaaaaa; font-style: italic } /* Comment.PreprocFile */
.listingblock .pygments .tok-c1 { color: #aaaaaa; font-style: italic } /* Comment.Single */
.listingblock .pygments .tok-cs { color: #0000aa; font-style: italic } /* Comment.Special */
.listingblock .pygments .tok-gd { color: #aa0000 } /* Generic.Deleted */
.listingblock .pygments .tok-ge { font-style: italic } /* Generic.Emph */
.listingblock .pygments .tok-gr { color: #aa0000 } /* Generic.Error */
.listingblock .pygments .tok-gh { color: #000080; font-weight: bold } /* Generic.Heading */
.listingblock .pygments .tok-gi { color: #00aa00 } /* Generic.Inserted */
.listingblock .pygments .tok-go { color: #888888 } /* Generic.Output */
.listingblock .pygments .tok-gp { color: #555555 } /* Generic.Prompt */
.listingblock .pygments .tok-gs { font-weight: bold } /* Generic.Strong */
.listingblock .pygments .tok-gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.listingblock .pygments .tok-gt { color: #aa0000 } /* Generic.Traceback */
.listingblock .pygments .tok-kc { color: #0000aa } /* Keyword.Constant */
.listingblock .pygments .tok-kd { color: #0000aa } /* Keyword.Declaration */
.listingblock .pygments .tok-kn { color: #0000aa } /* Keyword.Namespace */
.listingblock .pygments .tok-kp { color: #0000aa } /* Keyword.Pseudo */
.listingblock .pygments .tok-kr { color: #0000aa } /* Keyword.Reserved */
.listingblock .pygments .tok-kt { color: #00aaaa } /* Keyword.Type */
.listingblock .pygments .tok-m { color: #009999 } /* Literal.Number */
.listingblock .pygments .tok-s { color: #aa5500 } /* Literal.String */
.listingblock .pygments .tok-na { color: #1e90ff } /* Name.Attribute */
.listingblock .pygments .tok-nb { color: #00aaaa } /* Name.Builtin */
.listingblock .pygments .tok-nc { color: #00aa00; text-decoration: underline } /* Name.Class */
.listingblock .pygments .tok-no { color: #aa0000 } /* Name.Constant */
.listingblock .pygments .tok-nd { color: #888888 } /* Name.Decorator */
.listingblock .pygments .tok-ni { color: #880000; font-weight: bold } /* Name.Entity */
.listingblock .pygments .tok-nf { color: #00aa00 } /* Name.Function */
.listingblock .pygments .tok-nn { color: #00aaaa; text-decoration: underline } /* Name.Namespace */
.listingblock .pygments .tok-nt { color: #1e90ff; font-weight: bold } /* Name.Tag */
.listingblock .pygments .tok-nv { color: #aa0000 } /* Name.Variable */
.listingblock .pygments .tok-ow { color: #0000aa } /* Operator.Word */
.listingblock .pygments .tok-w { color: #bbbbbb } /* Text.Whitespace */
.listingblock .pygments .tok-mb { color: #009999 } /* Literal.Number.Bin */
.listingblock .pygments .tok-mf { color: #009999 } /* Literal.Number.Float */
.listingblock .pygments .tok-mh { color: #009999 } /* Literal.Number.Hex */
.listingblock .pygments .tok-mi { color: #009999 } /* Literal.Number.Integer */
.listingblock .pygments .tok-mo { color: #009999 } /* Literal.Number.Oct */
.listingblock .pygments .tok-sa { color: #aa5500 } /* Literal.String.Affix */
.listingblock .pygments .tok-sb { color: #aa5500 } /* Literal.String.Backtick */
.listingblock .pygments .tok-sc { color: #aa5500 } /* Literal.String.Char */
.listingblock .pygments .tok-dl { color: #aa5500 } /* Literal.String.Delimiter */
.listingblock .pygments .tok-sd { color: #aa5500 } /* Literal.String.Doc */
.listingblock .pygments .tok-s2 { color: #aa5500 } /* Literal.String.Double */
.listingblock .pygments .tok-se { color: #aa5500 } /* Literal.String.Escape */
.listingblock .pygments .tok-sh { color: #aa5500 } /* Literal.String.Heredoc */
.listingblock .pygments .tok-si { color: #aa5500 } /* Literal.String.Interpol */
.listingblock .pygments .tok-sx { color: #aa5500 } /* Literal.String.Other */
.listingblock .pygments .tok-sr { color: #009999 } /* Literal.String.Regex */
.listingblock .pygments .tok-s1 { color: #aa5500 } /* Literal.String.Single */
.listingblock .pygments .tok-ss { color: #0000aa } /* Literal.String.Symbol */
.listingblock .pygments .tok-bp { color: #00aaaa } /* Name.Builtin.Pseudo */
.listingblock .pygments .tok-fm { color: #00aa00 } /* Name.Function.Magic */
.listingblock .pygments .tok-vc { color: #aa0000 } /* Name.Variable.Class */
.listingblock .pygments .tok-vg { color: #aa0000 } /* Name.Variable.Global */
.listingblock .pygments .tok-vi { color: #aa0000 } /* Name.Variable.Instance */
.listingblock .pygments .tok-vm { color: #aa0000 } /* Name.Variable.Magic */
.listingblock .pygments .tok-il { color: #009999 } /* Literal.Number.Integer.Long */
</style>
</head>
<body class="article toc2 toc-left">
<div id="header">
<h1>MoonGLMATH Reference Manual</h1>
<div class="details">
<span id="author" class="author"><NAME></span><br>
<span id="revnumber">version 0.6,</span>
<span id="revdate">2020-02-29</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#_preface">Preface</a>
<ul class="sectlevel2">
<li><a href="#_getting_and_installing">Getting and installing</a></li>
<li><a href="#_module_organization">Module organization</a></li>
<li><a href="#_examples">Examples</a></li>
<li><a href="#_license">License</a></li>
<li><a href="#see-also">See also</a></li>
</ul>
</li>
<li><a href="#_introduction">Introduction</a></li>
<li><a href="#_vectors">Vectors</a></li>
<li><a href="#_matrices">Matrices</a></li>
<li><a href="#_quaternions">Quaternions</a></li>
<li><a href="#_boxes">Boxes</a></li>
<li><a href="#_complex_numbers">Complex numbers</a></li>
<li><a href="#_basic_transforms">Basic Transforms</a></li>
<li><a href="#_camera_and_projections">Camera and Projections</a></li>
<li><a href="#datahandling">Data handling</a></li>
<li><a href="#hostmem">Host memory objects</a></li>
<li><a href="#tracing">Tracing utilities</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<a class="image" href="http://www.lua.org"><img src="powered-by-lua.gif" alt="Lua logo"></a>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_preface">Preface</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This is the reference manual of <strong>MoonGLMATH</strong>, which is a
<a href="http://www.lua.org"><strong>Lua</strong></a> math library for
<a href="https://github.com/stetre/moongl"><strong>MoonGL</strong></a>.
<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup></p>
</div>
<div class="paragraph">
<p>It is assumed that the reader is familiar with the Lua programming language.</p>
</div>
<div class="paragraph">
<p>For convenience of reference, this document contains external (deep) links to the
<a href="http://www.lua.org/manual/5.3/manual.html">Lua Reference Manual</a>.</p>
</div>
<div class="sect2">
<h3 id="_getting_and_installing">Getting and installing</h3>
<div class="paragraph">
<p>For installation intructions, refer to the README file in the
<a href="https://github.com/stetre/moonglmath"><strong>MoonGLMATH official repository</strong></a>
on GitHub.</p>
</div>
</div>
<div class="sect2">
<h3 id="_module_organization">Module organization</h3>
<div class="paragraph">
<p>The MoonGLMATH module is loaded using Lua&#8217;s
<a href="http://www.lua.org/manual/5.3/manual.html#pdf-require">require</a>() and
returns a table containing the functions it provides
(as usual with Lua modules). This manual assumes that such
table is named <strong>glmath</strong>, i.e. that it is loaded with:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="pygments highlight"><code data-lang="lua"> <span class="tok-n">glmath</span> <span class="tok-o">=</span> <span class="tok-nb">require</span><span class="tok-p">(</span><span class="tok-s2">&quot;moonglmath&quot;</span><span class="tok-p">)</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>but nothing forbids the use of a different name.</p>
</div>
</div>
<div class="sect2">
<h3 id="_examples">Examples</h3>
<div class="paragraph">
<p>A few examples can be found in the <strong>examples/</strong> directory of the release package.</p>
</div>
</div>
<div class="sect2">
<h3 id="_license">License</h3>
<div class="paragraph">
<p>MoonGLMATH is released under the <strong>MIT/X11 license</strong> (same as
<a href="http://www.lua.org/license.html">Lua</a>, and with the same only requirement to give proper
credits to the original author).
The copyright notice is in the LICENSE file in the base directory
of the <a href="https://github.com/stetre/moonglmath">official repository</a> on GitHub.</p>
</div>
</div>
<div class="sect2">
<h3 id="see-also">See also</h3>
<div class="paragraph">
<p>MoonGLMATH is part of <a href="https://github.com/stetre/moonlibs">MoonLibs</a>, a collection of
Lua libraries for graphics and audio programming.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>MoonGLMATH is a basic graphics math library in Lua, intended to be used with
<a href="https://github.com/stetre/moongl">MoonGL</a> and the other libraries of the
<a href="https://github.com/stetre/moonlibs">MoonLibs collection</a> (but it does not depend on them, and viceversa).</p>
</div>
<div class="paragraph">
<p>By now it has only the minimal features needed for graphics programming: real vectors and real matrices
up to 4 and 4x4 dimensions, quaternions, 2D and 3D axis-aligned bounding boxes, complex numbers, and a few functions to generate transformation matrices.</p>
</div>
<div class="paragraph">
<p>Like MoonGL and the other <a href="#see-also">companion libraries</a>, it is not designed for
performance but for ease of use (the main purpose of these libraries is to lighten the burden
of programming while studying computer graphics).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_vectors">Vectors</h2>
<div class="sectionbody">
<div class="paragraph">
<p>MoonGLMATH supports row and column numeric vectors of size 2, 3, and 4.</p>
</div>
<div class="paragraph">
<p>A vector <strong>v</strong> is implemented as a table having the vector elements in the array part,
starting from index 1.
Additionally, it also has the non-array fields <strong>v.size</strong> (= <em>2</em>, <em>3</em>, or <em>4</em>) and
<strong>v.type</strong> (= '<em>column</em>' or '<em>row</em>').</p>
</div>
<div class="paragraph">
<p>Vector elements are Lua <a href="http://www.lua.org/manual/5.3/manual.html#2.1">number</a>s
and can be accessed through standard indexing (that is, <strong>v[1]</strong> is the first element, <strong>v[2]</strong>
is the second element and so on).</p>
</div>
<div class="paragraph">
<p>Vector elements can also be accessed using the <strong>xyzw</strong>, <strong>rgba</strong> and <strong>stpq</strong> syntactic sugar
for positions, colors and texture coordinates (<strong>v.x</strong>, <strong>v.r</strong> and <strong>v.s</strong> are aliases for <strong>v[1]</strong>,
<strong>v.y</strong>, <strong>v.g</strong> and <strong>v.t</strong> are aliases for <strong>v[2]</strong>, and so on).</p>
</div>
<div class="paragraph">
<p>The following constructors can be used to create vectors.</p>
</div>
<div id="glmath.vecN" class="ulist">
<ul>
<li>
<p><em>v</em> = <strong>vec2</strong>(<em>&#8230;&#8203;</em>)<br>
<em>v</em> = <strong>vec3</strong>(<em>&#8230;&#8203;</em>)<br>
<em>v</em> = <strong>vec4</strong>(<em>&#8230;&#8203;</em>)<br>
<em>v</em> = <strong>vec2r</strong>(<em>&#8230;&#8203;</em>)<br>
<em>v</em> = <strong>vec3r</strong>(<em>&#8230;&#8203;</em>)<br>
<em>v</em> = <strong>vec4r</strong>(<em>&#8230;&#8203;</em>)<br>
<span class="small">Create a vector.
The <strong>vecN</strong> function creates a column vector of size N (where N may be 2, 3 or 4), whereas the <strong>vecNr</strong> function creates a row vector of the same size. Values to initialize the vector elements may be optionally passed as a list of numbers, or as a previously created vector (exceeding values are discarded, while missing values are replaced with zeros).</span></p>
</li>
</ul>
</div>
<div id="glmath.tovecN" class="ulist">
<ul>
<li>
<p><em>t</em> = <strong>tovec2</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tovec3</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tovec4</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tovec2r</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tovec3r</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tovec4r</strong>(<em>t</em>)<br>
<span class="small">Turn an appropriately sized table into a vector, by adding the relevant meta information to it.</span></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">examples</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="lua"><span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec3</span><span class="tok-p">()</span>            <span class="tok-c1">--&gt; v = { 0, 0, 0 }&#39;</span>
<span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec3</span><span class="tok-p">(</span><span class="tok-mi">11</span><span class="tok-p">,</span> <span class="tok-mi">22</span><span class="tok-p">)</span>      <span class="tok-c1">--&gt; v = { 11, 22, 0 }&#39;</span>
<span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec2</span><span class="tok-p">(</span><span class="tok-n">v</span><span class="tok-p">)</span>           <span class="tok-c1">--&gt; v = { 11, 22 }&#39;</span>
<span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec4</span><span class="tok-p">(</span><span class="tok-n">v</span><span class="tok-p">)</span>           <span class="tok-c1">--&gt; v = { 11, 22, 0, 0 }&#39;</span>
<span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec2</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">)</span>  <span class="tok-c1">--&gt; v = { 1, 2 }&#39;</span></code></pre>
</div>
</div>
<div id="glmath.isvecN" class="ulist">
<ul>
<li>
<p><em>boolean</em> = <strong>isvec2</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>isvec3</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>isvec4</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>isvec2r</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>isvec3r</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>isvec4r</strong>(<em>v</em>)<br>
<span class="small">Check if <em>v</em> is a vector of a given type (e.g. <strong>isvec2r</strong> checks if <em>v</em> is a row vector of size 2).</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>Vectors have the following functions, also available as methods of their first argument:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>|v|</em> = <strong>norm</strong>(<em>v</em>)<br>
<em>|v|<sup>2</sup></em> = <strong>norm2</strong>(<em>v</em>)<br>
<em>v/|v|</em> = <strong>normalize</strong>(<em>v</em>)<br>
<em>v<sup>T</sup></em> = <strong>transpose</strong>(<em>v</em>)<br></p>
</li>
<li>
<p><em>v<sub>clamped</sub></em> = <strong>clamp</strong>(<em>v</em>, <em>v<sub>min</sub></em>, <em>v<sub>max</sub></em>)<br>
<span class="small">Element-wise clamp.</span></p>
</li>
<li>
<p><em>v<sub>mix</sub></em> = <strong>mix</strong>(<em>v</em>, <em>v<sub>1</sub></em>, <em>k</em>)<br>
<span class="small">Element-wise blend <em>v<sub>mix</sub> = (1-k)*v +k*v<sub>1</sub></em>, where <em>k</em> is a number.</span></p>
</li>
<li>
<p><em>v<sub>step</sub></em> = <strong>step</strong>(<em>v</em>, <em>v<sub>edge</sub></em>)<br>
<span class="small">Element-wise step: <em>v<sub>step</sub>=0.0</em> if <em>v&le;v<sub>edge</sub></em>,  <em>v<sub>step</sub>=1.0</em> otherwise (element subscripts are omitted for clarity).<br>
The <em>v<sub>edge</sub></em> argument may be a number, meaning a vector with all elements equal to that number.</span></p>
</li>
</ul>
</div>
<div id="vec_smoothstep" class="ulist">
<ul>
<li>
<p><em>v<sub>smoothstep</sub></em> = <strong>smoothstep</strong>(<em>v</em>, <em>v<sub>0</sub></em>, <em>v<sub>1</sub></em>)<br>
<span class="small">Element-wise smoothstep: omitting element subscripts, <em>v<sub>smoothstep</sub></em> is <em>0.0</em> if <em>v&le;v<sub>0</sub></em>,  <em>1.0</em> if <em>v&ge;v<sub>1</sub></em>, and is obtained by smooth Hermite interpolation if <em>v<sub>0</sub>&lt;v&lt;v<sub>1</sub></em>
(i.e. <em>v<sub>smoothstep</sub>=3t<sup>2</sup>-2t<sup>3</sup></em>, where <em>t=(v-v<sub>0</sub>)/(v<sub>1</sub>-v<sub>0</sub>)</em>). The result is undefined if <em>v<sub>0</sub>&ge;v<sub>1</sub></em>.<br>
The <em>v<sub>0</sub></em> and <em>v<sub>1</sub></em> argument may be both be a number, meaning a vector with all elements equal to that number.</span></p>
</li>
<li>
<p><em>v<sub>fade</sub></em> = <strong>fade</strong>(<em>v</em>, <em>v<sub>0</sub></em>, <em>v<sub>1</sub></em>)<br>
<span class="small">Element-wise improved smoothstep. Same as <a href="#vec_smoothstep">smoothstep</a>(&nbsp;), but with the smoother interpolation function <em>v<sub>fade</sub>=6t<sup>5</sup>-15t<sup>4</sup>+10t<sup>3</sup></em> (Perlin improved).</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>The following <strong>vector operators</strong> are supported:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Unary minus</strong>: <em>v = -v<sub>1</sub></em>.</p>
</li>
<li>
<p><strong>Addition</strong>: <em>v = v<sub>1</sub> + v<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Subtraction</strong>: <em>v = v<sub>1</sub> - v<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Multiplication by a scalar</strong>: <em>v = s * v1</em>, and <em>v = v<sub>1</sub> * s</em>, where <em>s</em> is a number.</p>
</li>
<li>
<p><strong>Division by a scalar</strong>: <em>v = v<sub>1</sub> / s</em>, where <em>s</em> is a number.</p>
</li>
<li>
<p><strong>Dot product</strong>: <em>s = v<sub>1</sub> * v<sub>2</sub></em>, where <em>v<sub>1</sub></em> and <em>v<sub>2</sub></em> are vectors of the same size (row*column, but row*row and column*column are accepted as well).</p>
</li>
<li>
<p><strong>Multiplication</strong>: <em>m = v<sub>1</sub> * v<sub>2</sub></em>, where <em>v<sub>1</sub></em> is a column vector and <em>v<sub>2</sub></em> is a row vector of the same size. The result is a square matrix.</p>
</li>
<li>
<p><strong>Cross product</strong>: <em>v = v<sub>1</sub> % v<sub>2</sub></em>, where <em>v<sub>1</sub></em> and <em>v<sub>3</sub></em> are size 3 vectors. Works also on operands of size 2 and 4, adapting them to size 3 (size 2 operands are extended to size 3 by adding a zero element, while size 4 operands are reduced to size 3 by ignoring the 4-th element).
The result is always a size 3 vector.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_matrices">Matrices</h2>
<div class="sectionbody">
<div class="paragraph">
<p>MoonGLMATH supports numeric matrices of size NxM, with N and M ranging from 2 to 4 inclusive.</p>
</div>
<div class="paragraph">
<p>A matrix <strong>m</strong> is implemented as a table having its rows in the array part,
starting from index 1; each row is also a table having the elements in the array part.
Additionally, the matrix also has the non-array fields <strong>m.rows</strong> and
<strong>m.columns</strong>, whose values are the number of rows and of columns, respectively.</p>
</div>
<div class="paragraph">
<p>Matrix elements are Lua <a href="http://www.lua.org/manual/5.3/manual.html#2.1">number</a>s
and can be accessed through standard indexing. That is, <strong>m[i][j]</strong> is the element in the
i-th row and j-th column of the matrix <strong>m</strong>.</p>
</div>
<div class="paragraph">
<p>Matrix elements can also be accessed using the <strong>m._ij</strong> syntactic sugar, with i and j
ranging from 1 to 4 inclusive, which is an alias for <strong>m[i][j]</strong> (e.g. <strong>m._23</strong> is the
same as <strong>m[2][3]</strong>).</p>
</div>
<div class="paragraph">
<p>The following constructors can be used to create matrices.</p>
</div>
<div id="glmath.matN" class="ulist">
<ul>
<li>
<p><em>m</em> = <strong>mat2</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat3</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat4</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat2x3</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat3x2</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat2x4</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat4x2</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat3x4</strong>(<em>&#8230;&#8203;</em>)<br>
<em>m</em> = <strong>mat4x3</strong>(<em>&#8230;&#8203;</em>)<br>
<span class="small">Create a matrix. The <strong>matN</strong> function creates a square matrix vector size NxN, while
the <strong>matNxM</strong> creates a rectangular matrix of size NxM.
Values to initialize the matrix elements may be optionally passed as a list of numbers
(to fill the matrix in row-major order), as a list of row vectors (to fill the matrix rows),
as a list of column vectors (to fill the matrix columns), or as a matrix (to copy the elements
from). In all cases, exceeding values are discarded, while missing values are replaced with zeros.
As an exception, the <strong>matN</strong> function, when invoked without arguments, returns the NxN
identity matrix.</span></p>
</li>
</ul>
</div>
<div id="glmath.tomatN" class="ulist">
<ul>
<li>
<p><em>t</em> = <strong>tomat2</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat3</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat4</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat2x3</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat3x2</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat2x4</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat4x2</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat3x4</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tomat4x3</strong>(<em>t</em>)<br>
<span class="small">Turn an appropriately sized table into a matrix, by adding the relevant meta information to it.</span></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">examples</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="lua"><span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat3</span><span class="tok-p">()</span>              <span class="tok-c1">--&gt; m = {{ 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }}</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat2x3</span><span class="tok-p">()</span>            <span class="tok-c1">--&gt; m = {{ 0, 0, 0 }, { 0, 0, 0 }}</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat2x3</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">)</span>  <span class="tok-c1">--&gt; m = {{ 1, 2, 3 }, { 4, 0, 0 }}</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat3x2</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">)</span>  <span class="tok-c1">--&gt; m = {{ 1, 2 }, { 3, 4 }, { 0, 0 }}</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat3</span><span class="tok-p">(</span><span class="tok-n">m</span><span class="tok-p">)</span>             <span class="tok-c1">--&gt; m = {{ 1, 2, 0 }, { 3, 4, 0 }, { 0, 0, 0 }}</span>
<span class="tok-n">v1</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec2</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">)</span>
<span class="tok-n">v2</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec2</span><span class="tok-p">(</span><span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">)</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat2</span><span class="tok-p">(</span><span class="tok-n">v1</span><span class="tok-p">,</span> <span class="tok-n">v2</span><span class="tok-p">)</span>        <span class="tok-c1">--&gt; m = {{ 1, 3 }, { 2, 4 }}</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat3</span><span class="tok-p">(</span><span class="tok-n">v1</span><span class="tok-p">,</span> <span class="tok-n">v2</span><span class="tok-p">)</span>        <span class="tok-c1">--&gt; m = {{ 1, 3, 0 }, { 2, 4, 0 }, { 0, 0, 0 }}</span>
<span class="tok-n">v1</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec2r</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">)</span>
<span class="tok-n">v2</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec2r</span><span class="tok-p">(</span><span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">)</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat2</span><span class="tok-p">(</span><span class="tok-n">v1</span><span class="tok-p">,</span> <span class="tok-n">v2</span><span class="tok-p">)</span>        <span class="tok-c1">--&gt; m = {{ 1, 2 }, { 3, 4 }}</span>
<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat3</span><span class="tok-p">(</span><span class="tok-n">v1</span><span class="tok-p">,</span> <span class="tok-n">v2</span><span class="tok-p">)</span>        <span class="tok-c1">--&gt; m = {{ 1, 2, 0 }, { 3, 4, 0 }, { 0, 0, 0 }}</span></code></pre>
</div>
</div>
<div id="glmath.ismatN" class="ulist">
<ul>
<li>
<p><em>boolean</em> = <strong>ismat2</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat3</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat4</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat2x3</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat3x2</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat2x4</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat4x2</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat3x4</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>ismat4x3</strong>(<em>v</em>)<br>
<span class="small">Check if <em>m</em> is a matrix of a given size (e.g. <strong>ismat2</strong> checks if <em>m</em> is a 2x2 matrix).</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>Matrices have the following <strong>functions and methods</strong> (functions are also available as methods of their first argument):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>determinant</em> = <strong>det</strong>(<em>m</em>)<br>
<em>trace</em> = <strong>trace</strong>(<em>m</em>)<br>
<em>adjoint</em> = <strong>adj</strong>(<em>m</em>)<br>
<em>m<sup>-1</sup></em> = <strong>inv</strong>(<em>m</em>)<br>
<span class="small">Apply only to square matrices. If <em>m</em> is singular, <em>inv(m)</em> returns <em>nil</em>.</span></p>
</li>
<li>
<p><em>m<sup>T</sup></em> = <strong>transpose</strong>(<em>m</em>)<br></p>
</li>
<li>
<p><em>q</em> = <a href="#glmath.quat"><strong>quat</strong></a>(<em>m</em>)<br></p>
</li>
<li>
<p><em>v</em> = <strong>m:row</strong>(<em>i</em>)<br>
<span class="small">Returns the <em>i-th</em> row as a row vector (<a href="#glmath.vecN">vecNr</a>).</span></p>
</li>
<li>
<p><em>v</em> = <strong>m:column</strong>(<em>i</em>)<br>
<span class="small">Returns the <em>i-th</em> column as a column vector (<a href="#glmath.vecN">vecN</a>).</span></p>
</li>
<li>
<p><em>m<sub>clamped</sub></em> = <strong>clamp</strong>(<em>m</em>, <em>m<sub>min</sub></em>, <em>m<sub>max</sub></em>)<br>
<span class="small">Element-wise clamp.</span></p>
</li>
<li>
<p><em>m<sub>mix</sub></em> = <strong>mix</strong>(<em>m</em>, <em>m<sub>1</sub></em>, <em>k</em>)<br>
<span class="small">Element-wise blend <em>m<sub>mix</sub> = (1-k)*m +k*m<sub>1</sub></em>, where <em>k</em> is a number.</span></p>
</li>
<li>
<p><em>m<sub>step</sub></em> = <strong>step</strong>(<em>m</em>, <em>m<sub>edge</sub></em>)<br>
<span class="small">Element-wise step: <em>m<sub>step</sub>=0.0</em> if <em>m&le;m<sub>edge</sub></em>,  <em>m<sub>step</sub>=1.0</em> otherwise (element subscripts are omitted for clarity).<br>
The <em>m<sub>edge</sub></em> argument may be a number, meaning a matrix with all elements equal to that number.</span></p>
</li>
</ul>
</div>
<div id="mat_smoothstep" class="ulist">
<ul>
<li>
<p><em>m<sub>smoothstep</sub></em> = <strong>smoothstep</strong>(<em>m</em>, <em>m<sub>0</sub></em>, <em>m<sub>1</sub></em>)<br>
<span class="small">Element-wise smoothstep: omitting element subscripts, <em>m<sub>smoothstep</sub></em> is <em>0.0</em> if <em>m&le;m<sub>0</sub></em>,  <em>1.0</em> if <em>m&ge;m<sub>1</sub></em>, and is obtained by smooth Hermite interpolation if <em>m<sub>0</sub>&lt;m&lt;m<sub>1</sub></em>
(i.e. <em>m<sub>smoothstep</sub>=3t<sup>2</sup>-2t<sup>3</sup></em>, where <em>t=(m-m<sub>0</sub>)/(m<sub>1</sub>-m<sub>0</sub>)</em>). The result is undefined if <em>m<sub>0</sub>&ge;m<sub>1</sub></em>.<br>
The <em>m<sub>0</sub></em> and <em>m<sub>1</sub></em> argument may be both be a number, meaning a matrix with all elements equal to that number.</span></p>
</li>
<li>
<p><em>m<sub>fade</sub></em> = <strong>fade</strong>(<em>m</em>, <em>m<sub>0</sub></em>, <em>m<sub>1</sub></em>)<br>
<span class="small">Element-wise improved smoothstep. Same as <a href="#mat_smoothstep">smoothstep</a>(&nbsp;), but with the smoother interpolation function <em>m<sub>fade</sub>=6t<sup>5</sup>-15t<sup>4</sup>+10t<sup>3</sup></em> (Perlin improved).</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>The following <strong>matrix operators</strong> are supported:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Unary minus</strong>: <em>m = -m<sub>1</sub></em>.</p>
</li>
<li>
<p><strong>Addition</strong>: <em>m = m<sub>1</sub> + m<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Subtraction</strong>: <em>m = m<sub>1</sub> - m<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Multiplication by a scalar</strong>: <em>m = s * m<sub>1</sub></em>, and <em>m = m<sub>1</sub> * s</em>, where <em>s</em> is a number.</p>
</li>
<li>
<p><strong>Division by a scalar</strong>: <em>m = m<sub>1</sub> / s</em>, where <em>s</em> is a number.</p>
</li>
<li>
<p><strong>Integer power</strong>: <em>m = m<sub>1</sub> ^ n</em>, where <em>m<sub>1</sub></em> is a square matrix and <em>n</em> is an integer.</p>
</li>
<li>
<p><strong>Matrix multiplication</strong>: <em>m = m<sub>1</sub> * m<sub>2</sub></em>, where <em>m<sub>1</sub></em> is a NxK matrix and <em>m<sub>2</sub></em> a KxM matrix.
The result <em>m</em> is an NxM matrix.</p>
</li>
<li>
<p><strong>Matrix-vector multiplication</strong>: <em>u</em> = <em>m</em> * <em>v</em> where <em>m</em> is an NxM matrix and <em>v</em> is a size M column vector. The result <em>u</em> is a size N column vector.</p>
</li>
<li>
<p><strong>Vector-matrix multiplication</strong>: <em>u</em> = <em>v</em> * <em>m</em> where <em>v</em> is a size N row vector and <em>m</em> is an NxM matrix. The result <em>u</em> is a size M row vector.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_quaternions">Quaternions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A quaternion <strong>q</strong> = (<em>w</em>, <strong>v</strong>) = <em>w</em> + i·<em>x</em> + j·<em>y</em> + k·<em>z</em> is implemented as a table having
the quaternion elements in the array part, starting from index 1.</p>
</div>
<div class="paragraph">
<p>Quaternion elements are Lua <a href="http://www.lua.org/manual/5.3/manual.html#2.1">number</a>s
and can be accessed through standard indexing (that is, <strong>q[1]</strong> is the scalar part <em>w</em>,
and <strong>q[2]</strong> to <strong>q[4]</strong> are the <em>x</em>, <em>y</em> and <em>z</em> components of the vector part, or imaginary part, <strong>v</strong>).</p>
</div>
<div class="paragraph">
<p>Quaternion elements can also be accessed using the <strong>wxyz</strong> syntactic sugar:
<strong>q.w</strong>, <strong>q.x</strong>, <strong>q.y</strong>, and <strong>q.z</strong> are aliases for <strong>q[1]</strong>, <strong>q[2]</strong>, <strong>q[3]</strong>, and <strong>q[4]</strong>, respectively.</p>
</div>
<div class="paragraph">
<p>The following constructor can be used to create quaternions.</p>
</div>
<div id="glmath.quat" class="ulist">
<ul>
<li>
<p><em>q</em> = <strong>quat</strong>([<em>w</em>], [<em>x</em>], [<em>y</em>], [<em>z</em>])<br>
<em>q</em> = <strong>quat</strong>(<em>w</em>, <em>v</em>)<br>
<em>q</em> = <strong>quat</strong>(<em>v<sub>axis</sub></em>, <em>angle</em>)<br>
<em>q</em> = <strong>quat</strong>(<em>q</em>)<br>
<em>q</em> = <strong>quat</strong>(<em>m</em>)<br>
<span class="small">Create a quaternion.
Values to initialize the quaternion elements may be optionally passed as
a list of numbers, as a scalar <em>w</em> and a vector <em>v</em>, or as a previously created quaternion <em>q</em>
(exceeding values are discarded, while missing values are replaced with zeros).
If a matrix <em>m</em> is passed instead, the constructor assumes - without checking it - that <em>m</em> is a
rotation matrix and returns the equivalent quaternion
(<em>m</em> may be either a 3x3 or a 4x4 matrix, in which case its upper-left 3x3 submatrix
is regarded as the rotation matrix).</span></p>
</li>
</ul>
</div>
<div id="glmath.toquat" class="ulist">
<ul>
<li>
<p><em>t</em> = <strong>toquat</strong>(<em>t</em>)<br>
<span class="small">Turn an appropriately sized table into a quaternion, by adding the relevant meta information to it.</span></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">examples</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="lua"><span class="tok-n">q</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">quat</span><span class="tok-p">()</span>            <span class="tok-c1">--&gt; q = &lt; 0, 0, 0 &gt;</span>
<span class="tok-n">q</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">quat</span><span class="tok-p">(</span><span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>  <span class="tok-c1">--&gt; q = &lt; 0, 1, 2, 3 &gt;</span>

<span class="tok-n">w</span> <span class="tok-o">=</span> <span class="tok-mi">0</span>
<span class="tok-n">v</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">vec3</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">)</span>
<span class="tok-n">q</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">quat</span><span class="tok-p">(</span><span class="tok-n">w</span><span class="tok-p">,</span> <span class="tok-n">v</span><span class="tok-p">)</span>        <span class="tok-c1">--&gt; q = &lt; 0, 1, 2, 3 &gt;</span>

<span class="tok-n">m</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">mat3</span><span class="tok-p">(</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">0</span><span class="tok-p">)</span>
<span class="tok-n">q</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">quat</span><span class="tok-p">(</span><span class="tok-n">m</span><span class="tok-p">)</span>           <span class="tok-c1">--&gt; q = &lt; 0.707107,  0.707107, 0, 0 &gt;</span></code></pre>
</div>
</div>
<div id="glmath.isquat" class="ulist">
<ul>
<li>
<p><em>boolean</em> = <strong>isquat</strong>(<em>q</em>)<br>
<span class="small">Returns <em>true</em> if <em>q</em> is a quaternion, <em>false</em> otherwise.</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>Quaternions have the following <strong>functions and methods</strong> (functions are also available as methods of their first argument):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>w</em>, <em>v</em> = <strong>parts</strong>(<em>q</em>)<br>
<span class="small">Returns the scalar and vector parts of <em>q</em> (<em>w</em> is a number and <em>v</em> is a <a href="#glmath.vecN">vec3</a>).</span></p>
</li>
<li>
<p><em>q<sup>*</sup></em> = <strong>conj</strong>(<em>q</em>)<br>
<em>|q|</em> = <strong>norm</strong>(<em>q</em>)<br>
<em>|q|<sup>2</sup></em> = <strong>norm2</strong>(<em>q</em>)<br>
<em>q/|q|</em> = <strong>normalize</strong>(<em>q</em>)<br>
<em>q<sup>-1</sup></em> = <strong>inv</strong>(<em>q</em>)<br></p>
</li>
<li>
<p><em>m</em> = <strong>q:mat3</strong>( )<br>
<em>m</em> = <strong>q:mat4</strong>( )<br>
<span class="small">Convert the quaternion <em>q</em> to a 3x3 or a 4x4 rotation matrix.</span></p>
</li>
<li>
<p><em>q<sub>mix</sub></em> = <strong>mix</strong>(<em>q</em>, <em>q<sub>1</sub></em>, <em>k</em>)<br>
<span class="small">Element-wise blend <em>q<sub>mix</sub> = (1-k)*q +k*q<sub>1</sub></em>, where <em>k</em> is a number.</span></p>
</li>
<li>
<p><em>q<sub>slerp</sub></em> = <strong>slerp</strong>(<em>q</em>, <em>q<sub>1</sub></em>, <em>k</em>)<br>
<span class="small">Spherical linear interpolation.</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>The following <strong>quaternion operators</strong> are supported:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Unary minus</strong>: <em>q = -q<sub>1</sub></em>.</p>
</li>
<li>
<p><strong>Addition</strong>: <em>q = q<sub>1</sub> + q<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Subtraction</strong>: <em>q = q<sub>1</sub> - q<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Multiplication by a scalar</strong>: <em>q = s * q<sub>1</sub></em>, and <em>q = q<sub>1</sub> * s</em>, where <em>s</em> is a number.</p>
</li>
<li>
<p><strong>Division by a scalar</strong>: <em>q = q<sub>1</sub> / s</em>, where <em>s</em> is a number.</p>
</li>
<li>
<p><strong>Integer power</strong>: <em>q = q<sub>1</sub> ^ n</em>, where <em>n</em> is an integer.</p>
</li>
<li>
<p><strong>Quaternion multiplication</strong>: <em>q = q<sub>1</sub> * q<sub>2</sub></em>.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_boxes">Boxes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>MoonGLMATH supports 2D and 3D axis-aligned bounding boxes.</p>
</div>
<div class="paragraph">
<p>A box <strong>b</strong> is implemented as a table having the field <strong>v.dimensions</strong> (= <em>2</em> or <em>3</em>),
and the coordinates of the vertices in the array part, starting from index 1, as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>{ minx, maxx, miny, maxy }</em> if <em>v.dimensions</em>=<em>2</em> (2D box), or</p>
</li>
<li>
<p><em>{ minx, maxx, miny, maxy, minz, maxz }</em> if <em>v.dimensions</em>=<em>3</em> (3D box).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The coordinates are Lua <a href="http://www.lua.org/manual/5.3/manual.html#2.1">number</a>s
and can be accessed through standard indexing (that is, <strong>b[1]</strong> is <em>minx</em>, <strong>b[2]</strong>
is <em>maxx</em>, and so on). They can also be accessed using the following syntactic sugar:
<strong>b.minx</strong> is an alias for <strong>b[1]</strong>, <strong>b.maxx</strong> is an alias for <strong>b[2]</strong>, and so on.</p>
</div>
<div class="paragraph">
<p>The following constructors can be used to create boxes.</p>
</div>
<div id="glmath.boxN" class="ulist">
<ul>
<li>
<p><em>b</em> = <strong>box2</strong>(<em>&#8230;&#8203;</em>)<br>
<em>b</em> = <strong>box3</strong>(<em>&#8230;&#8203;</em>)<br>
<span class="small">Create an axis-aligned bounding box.
The <strong>boxN</strong> function creates a N-dimensional box (where N may be 2 or 3). Values to initialize the box coordinates may be optionally passed as a list of numbers, or as a previously created box (exceeding values are discarded, while missing values are replaced with zeros). No consistency check is performed on the passed coordinates.</span></p>
</li>
</ul>
</div>
<div id="glmath.tovecN" class="ulist">
<ul>
<li>
<p><em>t</em> = <strong>tobox2</strong>(<em>t</em>)<br>
<em>t</em> = <strong>tobox3</strong>(<em>t</em>)<br>
<span class="small">Turn an appropriately sized table into a box, by adding the relevant meta information to it.</span></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">examples</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="lua"><span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">box2</span><span class="tok-p">()</span>               <span class="tok-c1">--&gt; b = [ 0, 0, 0, 0 ]</span>
<span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">box3</span><span class="tok-p">()</span>               <span class="tok-c1">--&gt; b = [ 0, 0, 0, 0, 0, 0 ]</span>
<span class="tok-n">b</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">box3</span><span class="tok-p">(</span><span class="tok-o">-</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-o">-</span><span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">)</span>   <span class="tok-c1">--&gt; b = [ -1, 1, -2, 2 ]</span></code></pre>
</div>
</div>
<div id="glmath.isboxN" class="ulist">
<ul>
<li>
<p><em>boolean</em> = <strong>isbox2</strong>(<em>v</em>)<br>
<em>boolean</em> = <strong>isbox3</strong>(<em>v</em>)<br>
<span class="small">Check if <em>b</em> is a box of the given dimensions (e.g. <strong>isbox2</strong> checks if <em>b</em> is a 2D box).</span></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_complex_numbers">Complex numbers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A complex number <strong>z</strong> = <em>re</em> + i·<em>im</em> (where <em>i</em> is the square root of <em>-1</em>) is implemented
as a table holding <em>re</em> and <em>im</em> in its array part (i.e. <em>{ re, im }</em>).</p>
</div>
<div class="paragraph">
<p>The real and imaginary parts are Lua <a href="http://www.lua.org/manual/5.3/manual.html#2.1">number</a>s
and can be accessed through standard indexing (that is, <strong>z[1]</strong> is the real part <em>re</em>, and <strong>z[2]</strong> is
the imaginary part <em>im</em>), or using the <strong>re-im</strong> syntactic sugar (<strong>z.re</strong> and <strong>z.im</strong> are aliases for <strong>z[1]</strong> and <strong>z[2]</strong>, respectively).</p>
</div>
<div class="paragraph">
<p>The following constructor can be used to create complex numbers:</p>
</div>
<div id="glmath.complex" class="ulist">
<ul>
<li>
<p><em>z</em> = <strong>complex</strong>([<em>re</em>], [<em>im</em>])<br>
<em>z</em> = <strong>complex</strong>(<em>z</em>)<br>
<em>{z<sub>1</sub>, z<sub>2</sub>, &#8230;&#8203;}</em> = <strong>complex</strong>(<em>{re<sub>1</sub>, im<sub>1</sub>, re<sub>2</sub>, im<sub>2</sub>, &#8230;&#8203;}</em>)<br>
<span class="small">Create a complex number from its real and imaginary parts (which default to <em>0</em>) or from a
previously created complex number <em>z</em>.</span></p>
</li>
</ul>
</div>
<div id="glmath.tocomplex" class="ulist">
<ul>
<li>
<p><em>t</em> = <strong>tocomplex</strong>(<em>t</em>)<br>
<span class="small">Turn an appropriately sized table into a complex number, by adding the relevant meta information to it.</span></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">examples</div>
<div class="content">
<pre class="pygments highlight"><code data-lang="lua"><span class="tok-n">z</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">complex</span><span class="tok-p">()</span>             <span class="tok-c1">--&gt; z = 0 + 0i</span>
<span class="tok-n">z</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">complex</span><span class="tok-p">(</span><span class="tok-mi">2</span><span class="tok-p">)</span>            <span class="tok-c1">--&gt; z = 2 + 0i</span>
<span class="tok-n">z</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">complex</span><span class="tok-p">(</span><span class="tok-kc">nil</span><span class="tok-p">,</span> <span class="tok-mi">5</span><span class="tok-p">)</span>       <span class="tok-c1">--&gt; z = 0 + 5i</span>
<span class="tok-n">z</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">complex</span><span class="tok-p">(</span><span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">)</span>         <span class="tok-c1">--&gt; z = 3 + 4i</span>
<span class="tok-n">w</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">complex</span><span class="tok-p">(</span><span class="tok-n">z</span><span class="tok-p">)</span>            <span class="tok-c1">--&gt; w = 3 + 4i</span>
<span class="tok-n">t</span> <span class="tok-o">=</span> <span class="tok-n">glmath</span><span class="tok-p">.</span><span class="tok-n">complex</span><span class="tok-p">({</span><span class="tok-mi">1</span><span class="tok-p">,</span> <span class="tok-mi">2</span><span class="tok-p">,</span> <span class="tok-mi">3</span><span class="tok-p">,</span> <span class="tok-mi">4</span><span class="tok-p">})</span> <span class="tok-c1">--&gt; t[1] = 1 + 2i, t[2] = 3 + 4i</span></code></pre>
</div>
</div>
<div id="glmath.iscomplex" class="ulist">
<ul>
<li>
<p><em>boolean</em> = <strong>iscomplex</strong>(<em>z</em>)<br>
<span class="small">Returns <em>true</em> if <em>z</em> is a complex number or a Lua number, <em>false</em> otherwise.</span></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>The complex functions and operators listed below are based on the C99 functions
for the complex type
(see <a href="https://en.wikipedia.org/wiki/C_mathematical_functions#complex.h">&lt;complex.h&gt;</a> or <em>man complex(7)</em> for more details).</p>
</div>
<div class="paragraph">
<p>Complex functions accept also real numbers (i.e. plain Lua numbers) as arguments, which they understand
as complex numbers with <em>im=0</em>. The same holds for binary complex operators,
where one of the two operands can be a real number (if both are, the standard Lua operators for
numbers are obviously used).</p>
</div>
<div class="paragraph">
<p>Complex <strong>functions</strong>, also available as methods for their first argument:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>re</em> = <strong>creal</strong>(<em>z</em>)<br>
<em>im</em> = <strong>cimag</strong>(<em>z</em>)<br>
<em>re</em>, <em>im</em> = <strong>parts</strong>(<em>z</em>)<br>
<em>|z|</em> = <strong>cabs</strong>(<em>z</em>)<br>
<em>|z|</em> = <strong>norm</strong>(<em>z</em>)<br>
<em>rad</em> = <strong>carg</strong>(<em>z</em>)<br>
<em>|z|<sup>2</sup></em> = <strong>norm2</strong>(<em>z</em>)<br>
<em>z/|z|</em> = <strong>normalize</strong>(<em>z</em>)<br>
<em>z<sup>*</sup></em> = <strong>conj</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>cproj</strong>(<em>z</em>)<br>
<em>z<sup>-1</sup></em> = <strong>inv</strong>(<em>z</em>)<br></p>
</li>
<li>
<p><em>e<sup>z</sup></em> = <strong>cexp</strong>(<em>z</em>)<br>
<em>ln(z)</em> = <strong>clog</strong>(<em>z</em>)<br>
<em>z<sup>1/2</sup></em> = <strong>csqrt</strong>(<em>z</em>)<br>
<em>z<sup>w</sup></em> = <strong>cpow</strong>(<em>z</em>, <em>w</em>)<br></p>
</li>
<li>
<p><em>z<sub>1</sub></em> = <strong>csin</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>ccos</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>ctan</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>casin</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>cacos</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>catan</strong>(<em>z</em>)<br></p>
</li>
<li>
<p><em>z<sub>1</sub></em> = <strong>csinh</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>ccosh</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>ctanh</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>casinh</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>cacosh</strong>(<em>z</em>)<br>
<em>z<sub>1</sub></em> = <strong>catanh</strong>(<em>z</em>)<br></p>
</li>
</ul>
</div>
<hr>
<div class="paragraph">
<p>Complex <strong>operators</strong>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Unary minus</strong>: <em>z = -z<sub>1</sub></em>.</p>
</li>
<li>
<p><strong>Addition</strong>: <em>z = z<sub>1</sub> + z<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Subtraction</strong>: <em>z = z<sub>1</sub> - z<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Multiplication</strong>: <em>z = z<sub>1</sub> * z<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Division</strong>: <em>z = z<sub>1</sub> / z<sub>2</sub></em>.</p>
</li>
<li>
<p><strong>Power</strong>: <em>z = z<sub>1</sub> ^ z<sub>2</sub></em>.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_basic_transforms">Basic Transforms</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><em>m</em> = <strong>translate</strong>(<em>v</em>)<br>
<em>m</em> = <strong>translate</strong>(<em>x</em> , <em>y</em> , <em>z</em>)<br>
<span class="small">Returns the 4x4 translation matrix, given the vector <em>v</em> or its components <em>x</em>, <em>y</em>, and <em>z</em>.</span></p>
</li>
<li>
<p><em>m</em> = <strong>scale</strong>(<em>v</em>)<br>
<em>m</em> = <strong>scale</strong>(<em>x</em>, [<em>y</em>] , [<em>z</em>])<br>
<span class="small">Returns the 4x4 scaling matrix, given the scaling factors <em>x</em>, <em>y</em>, and <em>z</em>, which may
also be passed as a vector.<br>
If <em>y</em> and <em>z</em> are not given, they are assumed equal to <em>x</em> (i.e. uniform scaling by a factor <em>x</em>).</span></p>
</li>
<li>
<p><em>m</em> = <strong>rotate</strong>(<em>angle</em>, <em>v</em>)<br>
<em>m</em> = <strong>rotate</strong>(<em>angle</em>, <em>x</em> , <em>y</em> , <em>z</em>)<br>
<span class="small">Return the 4x4 rotation matrix given the <em>angle</em> (in radians) and the direction vector
<em>v</em> = (<em>x</em>, <em>y</em>, <em>z</em>).</span></p>
</li>
<li>
<p><em>m</em> = <strong>rotate_x</strong>(<em>angle</em>)<br>
<em>m</em> = <strong>rotate_y</strong>(<em>angle</em>)<br>
<em>m</em> = <strong>rotate_z</strong>(<em>angle</em>)<br>
<span class="small">Return the 4x4 rotation matrix for a rotation by <em>angle</em> radians around the x, y or z axis, respectively.</span></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_camera_and_projections">Camera and Projections</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The functions below follow the traditional OpenGL conventions, where the camera (or viewer)
is in the origin, looking towards the negative z-axis, with the positive x-axis pointing to
its right and the positive y-axis pointing up, and the <em>near</em> and <em>far</em> parameters represent
the distance of the near and far planes from the origin along the viewing direction
(i.e. they are the negated z-coordinates of the two planes).</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>m</em> = <strong>look_at</strong>(<em>eye</em>, <em>at</em>, <em>up</em>)<br>
<span class="small">Returns a 4x4 matrix to transform from world coordinates to camera coordinates,
given the camera position and orientation in world coordinates:
<em>eye</em> is the camera position, <em>at</em> is its target point, and <em>up</em> is the
direction from the camera to a point on the vertical above the target.</span></p>
</li>
<li>
<p><em>m</em> = <strong>ortho</strong>(<em>left</em>, <em>right</em>, <em>bottom</em>, <em>top</em>, [<em>near</em>], [<em>far</em>])<br>
<span class="small">Returns a 4x4 ortographic projection matrix that transforms an axis-aligned box
into the axis-aligned cube of side 2 centered at the origin.<br>
The box is bounded by the planes <em>x=left</em>, <em>x=right</em>, <em>y=bottom</em>, <em>y=top</em>, <em>z=-near</em>, and <em>z=-far</em>.<br>
The <em>near</em> and <em>far</em> values default to -1.0 and 1.0 respectively (2D projection).</span></p>
</li>
<li>
<p><em>m</em> = <strong>frustum</strong>(<em>left</em>, <em>right</em>, <em>bottom</em>, <em>top</em>, <em>near</em>, <em>far</em>)<br>
<span class="small">Returns a 4x4 perspective projection matrix.
The view frustum has the center of projection in the origin, its near face is
the rectangle (<em>left&lt;x&lt;right</em>, <em>bottom&lt;y&lt;top</em>) in the <em>z=-near</em> plane, and its
far face is in the <em>z=-far</em> plane.</span></p>
</li>
<li>
<p><em>m</em> = <strong>perspective</strong>(<em>fovy</em>, <em>aspect</em>, <em>near</em>, <em>far</em>)<br>
<span class="small">Returns a 4x4 perspective projection matrix.
The view frustum has the center of projection in the origin, a vertical field of view given
by <em>fovy</em> (radians), and its near and far faces have the given <em>aspect</em> ratio (width/height),
and are at <em>z=-near</em> and <em>z=-far</em>, respectively.</span></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="datahandling">Data handling</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section describes additional utilities that can be used to encode data from Lua
variables to binary strings and viceversa.</p>
</div>
<div id="datahandling_flatten" class="ulist">
<ul>
<li>
<p><em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em> = <strong>flatten</strong>(<em>table</em>)<br>
<span class="small">Flattens out the given <em>table</em> and returns the terminal elements in the order they are found.<br>
Similar to Lua&#8217;s
<a href="http://www.lua.org/manual/5.3/manual.html#pdf-table.unpack">table.unpack</a>(&nbsp;), but it also unpacks
any nested table. Only the array part of the table and of nested tables is considered.</span></p>
</li>
</ul>
</div>
<div id="datahandling_flatten_table" class="ulist">
<ul>
<li>
<p>{<em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em>} = <strong>flatten_table</strong>(<em>table</em>)<br>
<span class="small">Same as <a href="#datahandling_flatten">flatten</a>(&nbsp;), but returns the values in a flat table.
Unlike <a href="#datahandling_flatten">flatten</a>(&nbsp;), this function can be used also with very large tables.</span></p>
</li>
</ul>
</div>
<div id="datahandling_sizeof" class="ulist">
<ul>
<li>
<p><em>size</em> = <strong>sizeof</strong>(<a href="#type"><em>type</em></a>)<br>
<span class="small">Returns the size in bytes of the given <em>type</em>.</span></p>
</li>
</ul>
</div>
<div id="datahandling_pack" class="ulist">
<ul>
<li>
<p><em>data</em> = <strong>pack</strong>(<a href="#type"><em>type</em></a>, <em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em>)<br>
<em>data</em> = <strong>pack</strong>(<a href="#type"><em>type</em></a>, <em>table</em>)<br>
<span class="small">Packs the numbers <em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em>, encoding  them according to the given <em>type</em>, and returns the resulting binary string.<br>
The values may also be passed in a (possibly nested) table. Only the array part of the table (and of nested tables) is considered.</span></p>
</li>
</ul>
</div>
<div id="datahandling_unpack" class="ulist">
<ul>
<li>
<p>{<em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em>} = <strong>unpack</strong>(<a href="#type"><em>type</em></a>, <em>data</em>)<br>
<span class="small">Unpacks the binary string <em>data</em>, interpreting it as a sequence of values of the given <em>type</em>,
and returns the extracted values in a flat table.<br>
The length of <em>data</em> must be a multiple of <a href="#datahandling_sizeof">sizeof</a>(<em>type</em>).</span></p>
</li>
</ul>
</div>
<div id="type" class="paragraph">
<p><span class="small"><strong>type</strong>: data types (and their corresponding C99 types)<br>
Values: '<em>char</em>' (int8_t), '<em>uchar</em>' (uint8_t), '<em>short</em>' (int16_t), '<em>ushort</em>' (uint16_t), '<em>int</em>' (int32_t), '<em>uint</em>' (uint32_t), '<em>long</em>' (int64_t), '<em>ulong</em>' (uint64_t), '<em>float</em>' (float), '<em>double</em>' (double).</span></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="hostmem">Host memory objects</h2>
<div class="sectionbody">
<div class="paragraph">
<p>An <strong>hostmem</strong> object encapsulates a pointer to host accessible memory
<sup class="footnote">[<a id="_footnoteref_2" class="footnote" href="#_footnote_2" title="View footnote.">2</a>]</sup>,
with methods to access it from Lua and to retrieve pointers to any of its locations in form of
<a href="http://www.lua.org/manual/5.3/manual.html#lua_pushlightuserdata">lightuserdata</a>.</p>
</div>
<div class="paragraph">
<p>The memory encapsulated by an hostmem object may be either memory allocated via
the <a href="#hostmem_malloc">glmath.malloc</a>(&nbsp;) or the <a href="#hostmem_aligned_alloc">glmath.aligned_alloc</a>(&nbsp;)
functions, or memory obtained by other means (e.g. mapped memory or shared virtual memory)
and passed to the <a href="#hostmem_hostmem">glmath.hostmem</a>(&nbsp;) constructor.</p>
</div>
<div class="paragraph">
<p>Hostmem objects are automatically deleted at exit, but they may also be deleted manually
via the <a href="#hostmem_free">glmath.free</a>(&nbsp;) function (or the corresponding method).</p>
</div>
<div id="hostmem_malloc" class="ulist">
<ul>
<li>
<p><em>hostmem</em> = <strong>malloc</strong>(<em>size</em>)<br>
<em>hostmem</em> = <strong>malloc</strong>(<em>data</em>)<br>
<em>hostmem</em> = <strong>malloc</strong>(<a href="#type"><em>type</em></a>, {<em>value<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>value<sub>N</sub></em>})<br>
<em>hostmem</em> = <strong>malloc</strong>(<a href="#type"><em>type</em></a>, <em>value<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>value<sub>N</sub></em>)<br>
<span class="small">Allocates host memory and creates an <em>hostmem</em> object to encapsulate it.<br>
<strong>malloc</strong>(<em>size</em>), where <em>size</em> is an integer, allocates <em>size</em> bytes of contiguous memory
and initializes them to 0;<br>
<strong>malloc</strong>(<em>data</em>), where <em>data</em> is a binary string, allocates <em>#data</em> bytes of contiguous
memory and initializes them with the contents of <em>data</em>;<br>
<strong>malloc</strong>(<em>type</em>, <em>&#8230;&#8203;</em>) is functionally equivalent to <em>malloc(glmath.pack(type, &#8230;&#8203;))</em>.</span></p>
</li>
</ul>
</div>
<div id="hostmem_aligned_alloc" class="ulist">
<ul>
<li>
<p><em>hostmem</em> = <strong>aligned_alloc</strong>(<em>alignment</em>, <em>size</em>)<br>
<em>hostmem</em> = <strong>aligned_alloc</strong>(<em>alignment</em>, <em>data</em>)<br>
<em>hostmem</em> = <strong>aligned_alloc</strong>(<em>alignment</em>, <a href="#type"><em>type</em></a>, {<em>value<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>value<sub>N</sub></em>})<br>
<em>hostmem</em> = <strong>aligned_alloc</strong>(<em>alignment</em>, <a href="#type"><em>type</em></a>, <em>value<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>value<sub>N</sub></em>)<br>
<span class="small">Same as <a href="#hostmem_malloc">malloc</a>(&nbsp;), with the additional <em>alignment</em> parameter to control
memory address alignment (rfr. <em>aligned_alloc(3)</em>).</span></p>
</li>
</ul>
</div>
<div id="hostmem_hostmem" class="ulist">
<ul>
<li>
<p><em>hostmem</em> = <strong>hostmem</strong>(<em>size</em>, <em>ptr</em>)<br>
<em>hostmem</em> = <strong>hostmem</strong>(<em>data</em>)<br>
<span class="small">Creates a <em>hostmem</em> object encapsulating user provided memory.<br>
Such memory may be provided in form of a lightuserdata (<em>ptr</em>) containing a valid pointer to <em>size</em> bytes of contiguous memory, or as a binary string (<em>data</em>).<br>
In both cases, care must be taken that the memory area remains valid until the <em>hostmem</em> object is
deleted, or at least until it is accessed via its methods.
In the <em>data</em> case, this means ensuring that <em>data</em> is not garbage collected during the hostmem object lifetime.<br>
(Note that <em>malloc(data)</em> and <em>hostmem(data)</em> differ in that the former allocates memory and copies
<em>data</em> in it, while the latter just stores a pointer to <em>data</em>).</span></p>
</li>
</ul>
</div>
<div id="hostmem_free" class="ulist">
<ul>
<li>
<p><strong>free</strong>(<em>hostmem</em>)<br>
hostmem:<strong>free</strong>( )<br>
<span class="small">Deletes the <em>hostmem</em> object. If <em>hostmem</em> was created with
<a href="#hostmem_malloc">glmath.malloc</a>(&nbsp;) or <a href="#hostmem_aligned_alloc">glmath.aligned_alloc</a>(&nbsp;), this function also releases the encapsulated memory.</span></p>
</li>
</ul>
</div>
<div id="hostmem_ptr" class="ulist">
<ul>
<li>
<p><em>ptr</em>  = hostmem:<strong>ptr</strong>([<em>offset</em>=0], [<em>nbytes</em>=0])<br>
<span class="small">Returns a pointer (lightuserdata) to the location at <em>offset</em> bytes from the beginning of the encapsulated memory.<br>
Raises an error if the requested location is beyond the boundaries of the memory area, or if there are not at least <em>nbytes</em> of memory after it.</span></p>
</li>
</ul>
</div>
<div id="hostmem_size" class="ulist">
<ul>
<li>
<p><em>nbytes</em> = hostmem:<strong>size</strong>([<em>offset</em>=0])<br>
<em>nbytes</em> = hostmem:<strong>size</strong>(<em>ptr</em>)<br>
<span class="small">Returns the number of bytes of memory available after <em>offset</em> bytes from the beginning
of the encapsulated memory area, or after <em>ptr</em> (a lightuserdata obtained with hostmem:<a href="#hostmem_ptr">ptr</a>(&nbsp;)).</span></p>
</li>
</ul>
</div>
<div id="hostmem_read" class="ulist">
<ul>
<li>
<p><em>data</em> = hostmem:<strong>read</strong>([<em>offset</em>], [<em>nbytes</em>])<br>
{<em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em>} = hostmem:<strong>read</strong>([<em>offset</em>], [<em>nbytes</em>], <a href="#type"><em>type</em></a>)<br>
<span class="small">Reads <em>nbytes</em> of data starting from <em>offset</em>, and returns it as a binary string or as
a table of primitive values.<br>
The <em>offset</em> parameter defaults to 0, and <em>nbytes</em> defaults to the memory size minus <em>offset</em>.<br>
<em>hostmem:read(offset, nbytes, type)</em> is functionally equivalent to
<em>glmath.unpack(type, hostmem:read(offset, nbytes))</em>.</span></p>
</li>
</ul>
</div>
<div id="hostmem_write" class="ulist">
<ul>
<li>
<p>hostmem:<strong>write</strong>(<em>offset</em>, <em>nil</em>, <em>data</em>)<br>
hostmem:<strong>write</strong>(<em>offset</em>, <a href="#type"><em>type</em></a>, <em>val<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>val<sub>N</sub></em>)<br>
hostmem:<strong>write</strong>(<em>offset</em>, <a href="#type"><em>type</em></a>, {<em>value<sub>1</sub></em>, <em>&#8230;&#8203;</em>, <em>value<sub>N</sub></em>})<br>
<span class="small">Writes to the encapsulated memory area, starting from the byte at <em>offset</em>.<br>
<strong>write</strong>(<em>offset</em>, <em>nil</em>, <em>data</em>) writes the contents of <em>data</em> (a binary string);<br>
<strong>write</strong>(<em>offset</em>, <em>type</em>, <em>&#8230;&#8203;</em>) is equivalent to <em>write(offset, nil, glmath.pack(type, &#8230;&#8203;))</em>.</span></p>
</li>
</ul>
</div>
<div id="hostmem_copy" class="ulist">
<ul>
<li>
<p>hostmem:<strong>copy</strong>(<em>offset</em>, <em>size</em>, <em>srcptr</em>)<br>
hostmem:<strong>copy</strong>(<em>offset</em>, <em>size</em>, <em>srchostmem</em>, <em>srcoffset</em>)<br>
<span class="small">Copies <em>size</em> bytes to the encapsulated memory area, starting from the byte at <em>offset</em>.<br>
<strong>copy</strong>(<em>offset</em>, <em>size</em>, <em>srcptr</em>), copies the <em>size</em> bytes pointed to by <em>srcptr</em> (a lightuserdata).<br>
<strong>copy</strong>(<em>offset</em>, <em>size</em>, <em>srchostmem</em>, <em>srcoffset</em>), copies <em>size</em> bytes from the memory encapsulated
by <em>srchostmem</em> (a hostmem object), starting from the location at <em>srcoffset</em>.</span></p>
</li>
</ul>
</div>
<div id="hostmem_clear" class="ulist">
<ul>
<li>
<p>hostmem:<strong>clear</strong>(<em>offset</em>, <em>nbytes</em>, [<em>val</em>=0])<br>
<span class="small">Clears <em>nbytes</em> of memory starting from <em>offset</em>. If the <em>val</em> parameter is given,
the bytes are set to its value instead of 0 (<em>val</em> may be an integer or a character, i.e.
a string of length 1).</span></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="tracing">Tracing utilities</h2>
<div class="sectionbody">
<div id="trace_objects" class="ulist">
<ul>
<li>
<p><strong>trace_objects</strong>(<em>boolean</em>)<br>
<span class="small">Enable/disable tracing of objects creation and destruction (which by default
is disabled).<br>
If enabled, a printf is generated whenever an object is created or deleted,
indicating the object type and the value of its raw handle.</span></p>
</li>
</ul>
</div>
<div id="now" class="ulist">
<ul>
<li>
<p><em>t</em> = <strong>now</strong>(&nbsp;)<br>
<span class="small">Returns the current time in seconds (a Lua number).<br>
This is implemented with monotonic <em>clock_gettime(3)</em>, if available, or
with <em>gettimeofday(3)</em> otherwise.</span></p>
</li>
</ul>
</div>
<div id="since" class="ulist">
<ul>
<li>
<p><em>dt</em> = <strong>since</strong>(<em>t</em>)<br>
<span class="small">Returns the time in seconds (a Lua number) elapsed since the time <em>t</em>,
previously obtained with the <a href="#now">now</a>(&nbsp;) function.</span></p>
</li>
</ul>
</div>
<div id="stats" class="ulist">
<ul>
<li>
<p><em>mean</em>, <em>var</em>, <em>min</em>, <em>max</em> = <strong>stats</strong>(<em>{number}</em>)<br>
<span class="small">Computes the mean, variance, and the minimum and maximum values for the given array
of numbers.</span></p>
</li>
</ul>
</div>
<div id="dumpdata" class="ulist">
<ul>
<li>
<p><strong>dumpdata</strong>(<em>{number}</em>, <em>filename</em>, [<em>mode='w'</em>])<br>
<span class="small">Writes the given array of numbers to the given file file (plain ascii format, two columns index-value).<br>
The data can then be displayed, for example, using gnuplot (<em>gnuplot&gt; plot "filename" using 1:2 with lines</em>).<br>
<em>mode</em> is the same as in <a href="http://www.lua.org/manual/5.3/manual.html#pdf-io.open">io.open</a>(&nbsp;).</span></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="footnotes">
<hr>
<div class="footnote" id="_footnote_1">
<a href="#_footnoteref_1">1</a>. This manual is written in <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>, rendered with <a href="http://asciidoctor.org/">AsciiDoctor</a> and a CSS from the <a href="https://github.com/asciidoctor/asciidoctor-stylesheet-factory">AsciiDoctor Stylesheet Factory</a>. The PDF version is produced with <a href="https://github.com/asciidoctor/asciidoctor-pdf">AsciiDoctor-Pdf</a>.
</div>
<div class="footnote" id="_footnote_2">
<a href="#_footnoteref_2">2</a>. The term 'host' is here used as for the Khronos OpenCL specs, to denote the machine where the application is running, as opposed to a device such as a GPU.
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 0.6<br>
Last updated 2020-02-29 22:03:09 CET
</div>
</div>
</body>
</html>

<|start_filename|>examples/interactive.lua<|end_filename|>
-- Interactive MoonGLMATH
--
-- This script just globalizes the contents of the glmath and math tables,
-- (except for math.type(), otherwise we would loose the Lua type() function)
-- so that we can call them without the table name.
--
-- Run it in the standard Lua interpreter in interactive mode, and you will
-- have a Lua shell with all the glmath facilities:
--
-- $ lua -i interactive.lua
-- > 
--
--

glmath = require("moonglmath")

-- globalize all glmath functions:
for k, v in pairs(glmath) do
   if(k~="type") then _ENV[k] = v end
end

-- globalize all math functions (except for type()):
for k, v in pairs(math) do
   if(k~="type") then _ENV[k] = v end
end


<|start_filename|>moonglmath/complexsugar.lua<|end_filename|>
-- The MIT License (MIT)
--
-- Copyright (c) 2018 <NAME>
--
-- Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--

do
local mt = getmetatable(moonglmath.complex())
local methods = mt.__index

local rd = {} -- read functions
local wr = {} -- write indices

-- position components
rd.re = function(self) return self[1] end
rd.im = function(self) return self[2] end
wr.re, wr.im = 1,2

mt.__index = function(self, key) 
	local f = rd[key]
	if f then return f(self) end
	return methods[key]
end

mt.__newindex = function(self, key, val)
	if type(key) == "number" then
		rawset(self, key, val)
		return
	end
	local i = wr[key]
	if i then 
		rawset(self, i, val)
	else
		error("cannot write field '" .. key .."'", 2)
	end
end

moonglmath.tocomplex = function(t) setmetatable(t, mt) return t end

end


<|start_filename|>src/num.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Functions acting on plain numbers (double)                                   |
 *------------------------------------------------------------------------------*/

double clamp(double x, double minval, double maxval)
    {
    if(x < minval) return minval;
    if(x > maxval) return maxval;
    return x;
    }

int num_Clamp(lua_State *L)
    {
    double x = luaL_checknumber(L, 1);
    double minval = luaL_checknumber(L, 2);
    double maxval = luaL_checknumber(L, 3);
    lua_pushnumber(L, clamp(x, minval, maxval));
    return 1;
    }

double mix(double x, double y, double k)
    {
    return x*(1.0-k) + y*k;
    }

int num_Mix(lua_State *L)
    {
    double x = luaL_checknumber(L, 1);
    double y = luaL_checknumber(L, 2);
    double k = luaL_checknumber(L, 3);
    lua_pushnumber(L, mix(x, y, k));
    return 1;
    }

double step(double x, double edge)
    {
    return x<=edge ? 0.0 : 1.0;
    }

int num_Step(lua_State *L)
    {
    double x = luaL_checknumber(L, 1);
    double edge = luaL_checknumber(L, 2);
    lua_pushnumber(L, step(x, edge));
    return 1;
    }

double smoothstep(double x, double edge0, double edge1)
    {
    double t = clamp((x-edge0)/(edge1-edge0), 0, 1);
    return t*t*(3-2*t);
    }

int num_Smoothstep(lua_State *L)
    {
    double x = luaL_checknumber(L, 1);
    double edge0 = luaL_checknumber(L, 2);
    double edge1 = luaL_checknumber(L, 3);
    lua_pushnumber(L, smoothstep(x, edge0, edge1));
    return 1;
    }

double fade(double x, double edge0, double edge1)
    {
    double t = clamp((x-edge0)/(edge1-edge0), 0, 1);
    return t*t*t*(t*(t*6-15)+10); // 6t^5 - 15t^4 + 10t^3 (Perlin's improved smoothstep)
    }

int num_Fade(lua_State *L)
    {
    double x = luaL_checknumber(L, 1);
    double edge0 = luaL_checknumber(L, 2);
    double edge1 = luaL_checknumber(L, 3);
    lua_pushnumber(L, fade(x, edge0, edge1));
    return 1;
    }



<|start_filename|>examples/vectors.lua<|end_filename|>
#!/usr/bin/env lua
-- MoonGLMATH example: vectors.lua

local glmath = require("moonglmath")

local v = glmath.vec3()
print(v)

v = glmath.vec3(11, 22)
print(v)

v = glmath.vec2(v)
print(v)

v = glmath.vec4(v)
print(v)

v = glmath.vec2(1, 2, 3, 4)
print(v)

local e1 = glmath.vec3(1,0,0)
local e2 = glmath.vec3(0,1,0)
local e3 = glmath.vec3(0,0,1)
print("canonical basis", e1, e2, e3)

print("transpose", v, v:transpose())
print("norm", v, v:norm())
print("unary minus", v, -v)
print("addition", v, v+v)
print("subtraction", v, v-v)
print("multiplication by a scalar", v, 2*v, v*2)
print("division by a scalar", v, v/2)
print("dot product", v, v*v)
print("cross product", e1, e2, e1%e2)



<|start_filename|>src/transform.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | Elementary transforms                                                        |
 *------------------------------------------------------------------------------*/

void translate(mat_t m, double x, double y, double z)
/* 1 0 0 x
 * 0 1 0 y
 * 0 0 1 z
 * 0 0 0 1
 *
 * T^-1(x,y,z) = T(-x, -y, -z)
 */
    {
    mat_clear(m);
    m[0][3] = x;
    m[1][3] = y;
    m[2][3] = z;
    m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
    }

void scale(mat_t m, double x, double y, double z)
/* x 0 0 0
 * 0 y 0 0
 * 0 0 z 0
 * 0 0 0 1
 */
    {
    mat_clear(m);
    m[0][0] = x;
    m[1][1] = y;
    m[2][2] = z;
    m[3][3] = 1.0;
    }

static void rotate(mat_t m, double x, double y, double z, double rad)
/* c+(1-c)x^2  (1-c)xy-sz (1-c)xz+sy  0
 * (1-c)xy+sz  c+(1-c)y^2 (1-c)yz-sx  0
 * (1-c)xz-sy  (1-c)yz+sx c+(1-c)z^2  0
 *     0           0          0       1
 *
 * c=cos(rad) s=sin(rad)
 */
    {
    double s, c, c1, a, b;
    c = cos(rad);
    s = sin(rad);
    c1 = 1.0 - c;
    mat_clear(m); 
    m[0][0] = c + c1 * x*x;
    m[1][1] = c + c1 * y*y;
    m[2][2] = c + c1 * z*z;
    m[3][3] = 1;
    a = c1*x*y; b = s*z;
    m[0][1] = a - b;
    m[1][0] = a + b;
    a = c1*x*z; b = s*y;
    m[0][2] = a + b;
    m[2][0] = a - b;
    a = c1*y*z; b = s*x;
    m[1][2] = a - b;
    m[2][1] = a + b;
    }


void rotate_x(mat_t m, double rad)
/*  1  0  0  0
 *  0  c -s  0
 *  0  s  c  0
 *  0  0  0  1
 */
    {
    double c = cos(rad);
    double s = sin(rad);
    mat_clear(m);
    m[0][0] = m[3][3] = 1;
    m[1][1] = m[2][2] = c;
    m[1][2] = -s;
    m[2][1] = s;
    }

void rotate_y(mat_t m, double rad)
/*  c  0  s  0
 *  0  1  0  0
 * -s  0  c  0
 *  0  0  0  1
 */
    {
    double c = cos(rad);
    double s = sin(rad);
    mat_clear(m);
    m[1][1] = m[3][3] = 1;
    m[0][0] = m[2][2] = c;
    m[2][0] = -s;
    m[0][2] = s;
    }

void rotate_z(mat_t m, double rad)
/*  c -s  0  0
 *  s  c  0  0
 *  0  0  1  0
 *  0  0  0  1
 */
    {
    double c = cos(rad);
    double s = sin(rad);
    mat_clear(m);
    m[0][0] = m[1][1] = c;
    m[2][2] = m[3][3] = 1;
    m[0][1] = -s;
    m[1][0] = s;
    }


static int Translate(lua_State *L)
    {
    vec_t v;
    mat_t m;
    if(!testvec(L, 1, v, NULL, NULL)) 
        {
        v[0] = luaL_checknumber(L, 1);
        v[1] = luaL_checknumber(L, 2);
        v[2] = luaL_checknumber(L, 3);
        }
    translate(m, v[0], v[1], v[2]);
    return pushmat(L, m, 4, 4, 4, 4);
    }

static int Scale(lua_State *L)
    {
    vec_t v;
    mat_t m;
    if(!testvec(L, 1, v, NULL, NULL)) 
        {
        v[0] = luaL_checknumber(L, 1);
        if(lua_isnoneornil(L, 2) && lua_isnoneornil(L, 3))
            v[1] = v[2] = v[0];
        else
            {
            v[1] = luaL_checknumber(L, 2);
            v[2] = luaL_checknumber(L, 3);
            }
        }
    scale(m, v[0], v[1], v[2]);
    return pushmat(L, m, 4, 4, 4, 4);
    }


static int Rotate(lua_State *L)
    {
    vec_t v;
    mat_t m;
    double rad = luaL_checknumber(L, 1);
    if(!testvec(L, 2, v, NULL, NULL)) 
        {
        v[0] = luaL_checknumber(L, 2);
        v[1] = luaL_checknumber(L, 3);
        v[2] = luaL_checknumber(L, 4);
        }
    rotate(m, v[0], v[1], v[2], rad);
    return pushmat(L, m, 4, 4, 4, 4);
    }


static int RotateX(lua_State *L)
    {
    mat_t m;
    double rad = luaL_checknumber(L, 1);
    rotate_x(m, rad);
    return pushmat(L, m, 4, 4, 4, 4);
    }

static int RotateY(lua_State *L)
    {
    mat_t m;
    double rad = luaL_checknumber(L, 1);
    rotate_y(m, rad);
    return pushmat(L, m, 4, 4, 4, 4);
    }

static int RotateZ(lua_State *L)
    {
    mat_t m;
    double rad = luaL_checknumber(L, 1);
    rotate_z(m, rad);
    return pushmat(L, m, 4, 4, 4, 4);
    }

/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "translate", Translate },
        { "scale", Scale },
        { "rotate", Rotate },
        { "rotate_x", RotateX },
        { "rotate_y", RotateY },
        { "rotate_z", RotateZ },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_transform(lua_State *L)
    {
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>src/objects.h<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2018 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef objectsDEFINED
#define objectsDEFINED

#include "tree.h"
#include "udata.h"

/* host accessible memory: */
typedef struct {
    char *ptr; 
    size_t size;
} hostmem_t;

/*------------------------------------------------------*/

/* Objects' metatable names */
#define HOSTMEM_MT "moonglmath_hostmem"

/* Userdata memory associated with objects */
#define ud_t moonglmath_ud_t
typedef struct moonglmath_ud_s ud_t;

struct moonglmath_ud_s {
    void *handle; /* the object handle bound to this userdata */
    int (*destructor)(lua_State *L, ud_t *ud);  /* self destructor */
    ud_t *parent_ud; /* the ud of the parent object */
    uint32_t marks;
    void *info; /* object specific info (ud_info_t, subject to Free() at destruction, if not NULL) */
};
    
/* Marks.  m_ = marks word (uint32_t) , i_ = bit number (0 .. 31)  */
#define MarkGet(m_,i_)  (((m_) & ((uint32_t)1<<(i_))) == ((uint32_t)1<<(i_)))
#define MarkSet(m_,i_)  do { (m_) = ((m_) | ((uint32_t)1<<(i_))); } while(0)
#define MarkReset(m_,i_) do { (m_) = ((m_) & (~((uint32_t)1<<(i_)))); } while(0)

#define IsValid(ud)             MarkGet((ud)->marks, 0)
#define MarkValid(ud)           MarkSet((ud)->marks, 0) 
#define CancelValid(ud)         MarkReset((ud)->marks, 0)

#define IsAllocated(ud)         MarkGet((ud)->marks, 1)
#define MarkAllocated(ud)       MarkSet((ud)->marks, 1) 
#define CancelAllocated(ud)     MarkReset((ud)->marks, 1)

#if 0
/* .c */
#define  moonglmath_
#endif

#define newuserdata moonglmath_newuserdata
ud_t *newuserdata(lua_State *L, void *handle, const char *mt, const char *tracename);
#define freeuserdata moonglmath_freeuserdata
int freeuserdata(lua_State *L, ud_t *ud, const char *tracename);
#define pushuserdata moonglmath_pushuserdata 
int pushuserdata(lua_State *L, ud_t *ud);

#define userdata_unref(L, handle) udata_unref((L),(handle))

#define UD(handle) userdata((handle)) /* dispatchable objects only */
#define userdata moonglmath_userdata
ud_t *userdata(void *handle);
#define testxxx moonglmath_testxxx
void *testxxx(lua_State *L, int arg, ud_t **udp, const char *mt);
#define checkxxx moonglmath_checkxxx
void *checkxxx(lua_State *L, int arg, ud_t **udp, const char *mt);
#define pushxxx moonglmath_pushxxx
int pushxxx(lua_State *L, void *handle);
#define checkxxxlist moonglmath_checkxxxlist
void** checkxxxlist(lua_State *L, int arg, uint32_t *count, int *err, const char *mt);

#define freechildren moonglmath_freechildren
int freechildren(lua_State *L,  const char *mt, ud_t *parent_ud);

/* hostmem.c */
#define checkhostmem(L, arg, udp) (hostmem_t*)checkxxx((L), (arg), (udp), HOSTMEM_MT)
#define testhostmem(L, arg, udp) (hostmem_t*)testxxx((L), (arg), (udp), HOSTMEM_MT)
#define pushhostmem(L, handle) pushxxx((L), (handle))
#define checkhostmemlist(L, arg, count, err) (hostmem_t*)checkxxxlist((L), (arg), (count), (err), HOSTMEM_MT)

/* used in main.c */
void moonglmath_open_hostmem(lua_State *L);

#define RAW_FUNC(xxx)                       \
static int Raw(lua_State *L)                \
    {                                       \
    lua_pushinteger(L, (uintptr_t)check##xxx(L, 1, NULL));  \
    return 1;                               \
    }

#define TYPE_FUNC(xxx)                      \
static int Type(lua_State *L)               \
    {                                       \
    (void)check##xxx(L, 1, NULL);           \
    lua_pushstring(L, ""#xxx);              \
    return 1;                               \
    }

#define DELETE_FUNC(xxx)                    \
static int Delete(lua_State *L)             \
    {                                       \
    ud_t *ud;                               \
    (void)test##xxx(L, 1, &ud);             \
    if(!ud) return 0; /* already deleted */ \
    return ud->destructor(L, ud);           \
    }

#endif /* objectsDEFINED */


<|start_filename|>src/funcs.c<|end_filename|>
/* The MIT License (MIT)
 *
 * Copyright (c) 2016 <NAME>
 *
 * Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "internal.h"

/*------------------------------------------------------------------------------*
 | glmath functions                                                             |
 *------------------------------------------------------------------------------*/

#define badarg(L, arg) luaL_argerror((L), (arg), "invalid argument type")

static int Det(lua_State *L)
    {
    if(ismat(L,1)) return mat_Det(L);
    return badarg(L, 1);
    }

static int Adj(lua_State *L)
    {
    if(ismat(L,1)) return mat_Adj(L);
    return badarg(L, 1);
    }

static int Inv(lua_State *L)
    {
    if(ismat(L,1)) return mat_Inv(L);
    if(isquat(L,1)) return quat_Inv(L);
    if(iscomplex(L,1)) return complex_Inv(L);
    return badarg(L, 1);
    }


static int Norm(lua_State *L)
    {
    if(isvec(L,1)) return vec_Norm(L);
    if(isquat(L,1)) return quat_Norm(L);
    if(iscomplex(L,1)) return complex_Norm(L);
    return badarg(L, 1);
    }

static int Norm2(lua_State *L)
    {
    if(isvec(L,1)) return vec_Norm2(L);
    if(isquat(L,1)) return quat_Norm2(L);
    if(iscomplex(L,1)) return complex_Norm2(L);
    return badarg(L, 1);
    }

static int Conj(lua_State *L)
    {
    if(isquat(L,1)) return quat_Conj(L);
    if(iscomplex(L,1)) return complex_Conj(L);
    return badarg(L, 1);
    }

static int Parts(lua_State *L)
    {
    if(isquat(L,1)) return quat_Parts(L);
    if(iscomplex(L,1)) return complex_Parts(L);
    return badarg(L, 1);
    }

static int Normalize(lua_State *L)
    {
    if(isvec(L,1)) return vec_Normalize(L);
    if(isquat(L,1)) return quat_Normalize(L);
    if(iscomplex(L,1)) return complex_Normalize(L);
    return badarg(L, 1);
    }


static int Trace(lua_State *L)
    {
    if(ismat(L,1)) return mat_Trace(L);
    return badarg(L, 1);
    }

static int Transpose(lua_State *L)
    {
    if(isvec(L,1)) return vec_Transpose(L);
    if(ismat(L,1)) return mat_Transpose(L);
    return badarg(L, 1);
    }

static int Row(lua_State *L)
    {
    if(ismat(L,1)) return mat_Row(L);
    return badarg(L, 1);
    }

static int Column(lua_State *L)
    {
    if(ismat(L,1)) return mat_Column(L);
    return badarg(L, 1);
    }

static int Clamp(lua_State *L)
    {
    if(lua_isnumber(L,1)) return num_Clamp(L);
    if(isvec(L,1)) return vec_Clamp(L);
    if(ismat(L,1)) return mat_Clamp(L);
    return badarg(L, 1);
    }

static int Mix(lua_State *L)
    {
    if(lua_isnumber(L,1)) return num_Mix(L);
    if(isvec(L,1)) return vec_Mix(L);
    if(ismat(L,1)) return mat_Mix(L);
    if(isquat(L,1)) return quat_Mix(L);
    return badarg(L, 1);
    }

static int Slerp(lua_State *L)
    {
    if(isquat(L,1)) return quat_Slerp(L);
    return badarg(L, 1);
    }

static int Step(lua_State *L)
    {
    if(lua_isnumber(L,1)) return num_Step(L);
    if(isvec(L,1)) return vec_Step(L);
    if(ismat(L,1)) return mat_Step(L);
    return badarg(L, 1);
    }

static int Smoothstep(lua_State *L)
    {
    if(lua_isnumber(L,1)) return num_Smoothstep(L);
    if(isvec(L,1)) return vec_Smoothstep(L);
    if(ismat(L,1)) return mat_Smoothstep(L);
    return badarg(L, 1);
    }

static int Fade(lua_State *L)
    {
    if(lua_isnumber(L,1)) return num_Fade(L);
    if(isvec(L,1)) return vec_Fade(L);
    if(ismat(L,1)) return mat_Fade(L);
    return badarg(L, 1);
    }

/*------------------------------------------------------------------------------*
 | Registration                                                                 |
 *------------------------------------------------------------------------------*/

static const struct luaL_Reg Functions[] = 
    {
        { "adj", Adj },
        { "det", Det },
        { "inv", Inv },
        { "norm", Norm },
        { "norm2", Norm2 },
        { "conj", Conj },
        { "parts", Parts },
        { "normalize", Normalize },
        { "trace", Trace },
        { "transpose", Transpose },
        { "row", Row },
        { "column", Column },
        { "clamp", Clamp },
        { "mix", Mix },
        { "slerp", Slerp },
        { "step", Step },
        { "smoothstep", Smoothstep },
        { "fade", Fade },
        { NULL, NULL } /* sentinel */
    };

void moonglmath_open_funcs(lua_State *L)
    {
    luaL_setfuncs(L, Functions, 0);
    }



<|start_filename|>moonglmath/matsugar.lua<|end_filename|>
-- The MIT License (MIT)
--
-- Copyright (c) 2016 <NAME>
--
-- Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--

do
local mt = getmetatable(moonglmath.mat2())
local methods = mt.__index

local rd = {} -- read functions
local wr = {} -- write indices

-- position components
rd._11 = function(self) return self[1][1] end
rd._12 = function(self) return self[1][2] end
rd._13 = function(self) return self[1][3] end
rd._14 = function(self) return self[1][4] end
rd._21 = function(self) return self[2][1] end
rd._22 = function(self) return self[2][2] end
rd._23 = function(self) return self[2][3] end
rd._24 = function(self) return self[2][4] end
rd._31 = function(self) return self[3][1] end
rd._32 = function(self) return self[3][2] end
rd._33 = function(self) return self[3][3] end
rd._34 = function(self) return self[3][4] end
rd._41 = function(self) return self[4][1] end
rd._42 = function(self) return self[4][2] end
rd._43 = function(self) return self[4][3] end
rd._44 = function(self) return self[4][4] end

wr._11 = function() return 1, 1 end
wr._12 = function() return 1, 2 end
wr._13 = function() return 1, 3 end
wr._14 = function() return 1, 4 end
wr._21 = function() return 2, 1 end
wr._22 = function() return 2, 2 end
wr._23 = function() return 2, 3 end
wr._24 = function() return 2, 4 end
wr._31 = function() return 3, 1 end
wr._32 = function() return 3, 2 end
wr._33 = function() return 3, 3 end
wr._34 = function() return 3, 4 end
wr._41 = function() return 4, 1 end
wr._42 = function() return 4, 2 end
wr._43 = function() return 4, 3 end
wr._44 = function() return 4, 4 end


mt.__index = function(self, key) 
	local f = rd[key]
	if f then return f(self) end
	return methods[key]
end

mt.__newindex = function(self, key, val)
	local f = wr[key]
	if f then 
		local i,j = f()
		local row = self[i]
		rawset(row, j, val)
	else
		rawset(self, key, val)
	end
end

moonglmath.tomat2 = function(t) setmetatable(t, mt) t.rows=2 t.columns=2 return t end
moonglmath.tomat3 = function(t) setmetatable(t, mt) t.rows=3 t.columns=3 return t end
moonglmath.tomat4 = function(t) setmetatable(t, mt) t.rows=4 t.columns=4 return t end
moonglmath.tomat2x3 = function(t) setmetatable(t, mt) t.rows=2 t.columns=3 return t end
moonglmath.tomat3x2 = function(t) setmetatable(t, mt) t.rows=3 t.columns=2 return t end
moonglmath.tomat2x4 = function(t) setmetatable(t, mt) t.rows=2 t.columns=4 return t end
moonglmath.tomat4x2 = function(t) setmetatable(t, mt) t.rows=4 t.columns=2 return t end
moonglmath.tomat3x4 = function(t) setmetatable(t, mt) t.rows=3 t.columns=4 return t end
moonglmath.tomat4x3 = function(t) setmetatable(t, mt) t.rows=4 t.columns=3 return t end

end


<|start_filename|>examples/matrices.lua<|end_filename|>
#!/usr/bin/env lua
-- MoonGLMATH example: matrices.lua

local glmath = require("moonglmath")

local m = glmath.mat3()
print(m)

m = glmath.mat2x3()
print(m)

m = glmath.mat2x3(1, 2, 3, 4)
print(m)

m = glmath.mat3x2(1, 2, 3, 4)
print(m)

m = glmath.mat3(m)
print(m)

local v1 = glmath.vec2(1, 2)
local v2 = glmath.vec2(3, 4)
m = glmath.mat2(v1, v2)
print(m)

m = glmath.mat3(v1, v2)
print(m)

v1 = glmath.vec2r(1, 2)
v2 = glmath.vec2r(3, 4)
m = glmath.mat2(v1, v2)
print(m)

m = glmath.mat3(v1, v2)
print(m)

m = glmath.mat2(1, 2, 3, 4)
print(m)

print("det", m, m:det())
print("trace", m, m:trace())
print("transpose", m, m:transpose())
print("adj", m, m:adj())
print("inv", m, m:inv(), m*m:inv())

print("unary minus", m, -m)
print("addition", m, m+m)
print("subtraction", m, m-m)
print("multiplication by a scalar", m, 2*m, m*2)
print("division by a scalar", m, m/2)
print("matrix multiplication", m, m*m)
local v = glmath.vec2(1, 2)
print("matrix-vector multiplication", m, m*v)


<|start_filename|>moonglmath/boxsugar.lua<|end_filename|>
-- The MIT License (MIT)
--
-- Copyright (c) 2016 <NAME>
--
-- Software repository: MoonGLMATH, https://github.com/stetre/moonglmath
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--


-- 
-- Adds named-components access to MoonGLMATH boxes
-- ( v.minx becomes an alias for b[1], v.maxx becomes an alias for b[2], and so on).
--

--local glmath = require("moonglmath")
--local mt = getmetatable(glmath.box2())
do
local mt = getmetatable(moonglmath.box2())
local methods = mt.__index

local rd = {} -- read functions
local wr = {} -- write indices

-- position components
rd.minx = function(self) return self[1] end
rd.maxx = function(self) return self[2] end
rd.miny = function(self) return self[3] end
rd.maxy = function(self) return self[4] end
rd.minz = function(self) return self[5] end
rd.maxz = function(self) return self[6] end
wr.minx, wr.maxx, wr.miny, wr.maxy, wr.minz, wr.maxz = 1,2,3,4,5,6

mt.__index = function(self, key) 
   local f = rd[key]
   if f then return f(self) end
   return methods[key]
end

mt.__newindex = function(self, key, val)
   if type(key) == "number" or key == "dimensions" then
      rawset(self, key, val)
      return
   end
   local i = wr[key]
   if i then 
      rawset(self, i, val)
   else
      error("cannot write field '" .. key .."'", 2)
   end
end

moonglmath.tobox2 = function(t) setmetatable(t, mt) t.dimensions=2 return t end
moonglmath.tobox3 = function(t) setmetatable(t, mt) t.dimensions=3 return t end

end


<|start_filename|>examples/quaternions.lua<|end_filename|>
#!/usr/bin/env lua
-- MoonGLMATH example: quaternions.lua

local glmath = require("moonglmath")

local q1 = glmath.quat(1, 2, 3, 4)
print(q1)

local q2 = glmath.quat(4, 3, 2, 1)
print(q2)


print("scalar and vector parts", q1, q1:parts())
print("unary minus", q1, -q1)
print("addition", q1, q2, q1+q2)
print("subtraction", q1, q2, q1-q2)
print("multiplication", q1, q2, q1*q2)
print("integer power", q1, q1^3, q1*q1*q1)
print("norm", q1, q1:norm()) -- also glmath.norm(q1)
print("conjugate", q1, q1:conj()) -- also glmath.conj(q1)
print("inverse", q1, q1:inv()) -- q^-1 would do also
print("multiplication by a scalar", q1, 2*q1, q1*2)
print("division by a scalar", q1, q1/2)
print("normalization", q1, q1:normalize()) -- glmath.normalize(q1)
print("3x3 rotation matrix", q1, q1:mat3())
print("4x4 rotation matrix", q1, q1:mat4())

-- create a quaternion representing a rotation
local axis, angle = glmath.vec3(0, 0, 1), math.pi/2
local q3 = glmath.quat(axis, angle)
print(q3, q3:norm())
-- compute the corresponding rotation matrix
local m = q3:mat3()
print(m)
-- apply the rotation to a vector:
print(m*glmath.vec3(1, 3, 5))
