From 37a18517eeef64ed541faa7fb187c6725aad0c00 Mon Sep 17 00:00:00 2001
From: cloudfreexiao <996442717qqcom@gmail.com>
Date: Thu, 15 Jul 2021 02:54:47 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=90=B3=20chore(=E5=B7=A5=E5=85=B7):=20?=
=?UTF-8?q?=E5=A2=9E=E5=8A=A0=20math3d?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitmodules | 9 +
framework/3rd/dmon/.clang-format | 38 +
framework/3rd/dmon/.gitignore | 72 +
framework/3rd/dmon/README.md | 75 +
framework/3rd/dmon/dmon.h | 1502 +++++++++++++++++
framework/3rd/dmon/test.c | 40 +
framework/3rd/ffi-lua | 1 +
framework/3rd/glm | 1 +
framework/3rd/moon | 1 +
framework/3rd/moon/.gitignore | 30 -
framework/3rd/moon/README.md | 552 ------
framework/3rd/moon/examples/dlfixex.c | 22 -
framework/3rd/moon/examples/flgex.c | 54 -
framework/3rd/moon/examples/objex.c | 528 ------
framework/3rd/moon/examples/plugin.c | 23 -
framework/3rd/moon/examples/plugin.h | 8 -
framework/3rd/moon/examples/sofix.c | 17 -
framework/3rd/moon/examples/stkex.c | 23 -
framework/3rd/moon/examples/test.lua | 135 --
framework/3rd/moon/moon.c | 1349 ---------------
framework/3rd/moon/moon.h | 237 ---
framework/3rd/moon/moon_dlfix.h | 183 --
framework/3rd/moon/moon_flag.h | 160 --
framework/lualib-src/lua-math3d/README.md | 5 -
framework/lualib-src/lua-math3d/lua-math3d.c | 853 ----------
framework/lualib-src/lua-math3d/math3d-left.h | 836 ---------
.../lualib-src/lua-math3d/math3d-right.h | 835 ---------
framework/lualib-src/math3d/.gitignore | 2 +
framework/lualib-src/math3d/Makefile | 43 +
framework/lualib-src/math3d/fastmath.h | 23 +
framework/lualib-src/math3d/linalg.c | 808 +++++++++
framework/lualib-src/math3d/linalg.h | 53 +
framework/lualib-src/math3d/math3d.c | 1344 +++++++++++++++
framework/lualib-src/math3d/math3d.h | 24 +
framework/lualib-src/math3d/math3dfunc.h | 45 +
framework/lualib-src/math3d/mathadapter.c | 538 ++++++
framework/lualib-src/math3d/mathfunc.cpp | 412 +++++
framework/lualib-src/math3d/refstack.h | 107 ++
framework/lualib-src/math3d/test.lua | 207 +++
framework/lualib-src/math3d/testadapter.c | 122 ++
framework/lualib-src/math3d/util.h | 27 +
41 files changed, 5494 insertions(+), 5850 deletions(-)
create mode 100755 framework/3rd/dmon/.clang-format
create mode 100755 framework/3rd/dmon/.gitignore
create mode 100755 framework/3rd/dmon/README.md
create mode 100755 framework/3rd/dmon/dmon.h
create mode 100755 framework/3rd/dmon/test.c
create mode 160000 framework/3rd/ffi-lua
create mode 160000 framework/3rd/glm
create mode 160000 framework/3rd/moon
delete mode 100644 framework/3rd/moon/.gitignore
delete mode 100644 framework/3rd/moon/README.md
delete mode 100644 framework/3rd/moon/examples/dlfixex.c
delete mode 100644 framework/3rd/moon/examples/flgex.c
delete mode 100644 framework/3rd/moon/examples/objex.c
delete mode 100644 framework/3rd/moon/examples/plugin.c
delete mode 100644 framework/3rd/moon/examples/plugin.h
delete mode 100644 framework/3rd/moon/examples/sofix.c
delete mode 100644 framework/3rd/moon/examples/stkex.c
delete mode 100755 framework/3rd/moon/examples/test.lua
delete mode 100644 framework/3rd/moon/moon.c
delete mode 100644 framework/3rd/moon/moon.h
delete mode 100644 framework/3rd/moon/moon_dlfix.h
delete mode 100644 framework/3rd/moon/moon_flag.h
delete mode 100644 framework/lualib-src/lua-math3d/README.md
delete mode 100644 framework/lualib-src/lua-math3d/lua-math3d.c
delete mode 100644 framework/lualib-src/lua-math3d/math3d-left.h
delete mode 100644 framework/lualib-src/lua-math3d/math3d-right.h
create mode 100755 framework/lualib-src/math3d/.gitignore
create mode 100755 framework/lualib-src/math3d/Makefile
create mode 100755 framework/lualib-src/math3d/fastmath.h
create mode 100755 framework/lualib-src/math3d/linalg.c
create mode 100755 framework/lualib-src/math3d/linalg.h
create mode 100755 framework/lualib-src/math3d/math3d.c
create mode 100755 framework/lualib-src/math3d/math3d.h
create mode 100755 framework/lualib-src/math3d/math3dfunc.h
create mode 100755 framework/lualib-src/math3d/mathadapter.c
create mode 100755 framework/lualib-src/math3d/mathfunc.cpp
create mode 100755 framework/lualib-src/math3d/refstack.h
create mode 100755 framework/lualib-src/math3d/test.lua
create mode 100755 framework/lualib-src/math3d/testadapter.c
create mode 100755 framework/lualib-src/math3d/util.h
diff --git a/.gitmodules b/.gitmodules
index b62a1d1..6cc4605 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,12 @@
[submodule "framework/3rd/goscon"]
path = framework/3rd/goscon
url = https://github.com/cloudfreexiao/goscon.git
+[submodule "framework/3rd/ffi-lua"]
+ path = framework/3rd/ffi-lua
+ url = https://github.com/cloudfreexiao/cffi-lua.git
+[submodule "framework/3rd/glm"]
+ path = framework/3rd/glm
+ url = https://github.com/g-truc/glm.git
+[submodule "framework/3rd/moon"]
+ path = framework/3rd/moon
+ url = https://github.com/siffiejoe/lua-moon.git
diff --git a/framework/3rd/dmon/.clang-format b/framework/3rd/dmon/.clang-format
new file mode 100755
index 0000000..61a73e2
--- /dev/null
+++ b/framework/3rd/dmon/.clang-format
@@ -0,0 +1,38 @@
+---
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: 'false'
+AlignConsecutiveDeclarations: 'false'
+AlignEscapedNewlines: Left
+AlignTrailingComments: 'true'
+AllowAllParametersOfDeclarationOnNextLine: 'true'
+AllowShortBlocksOnASingleLine: 'false'
+AllowShortCaseLabelsOnASingleLine: 'false'
+AllowShortFunctionsOnASingleLine: 'false'
+AllowShortIfStatementsOnASingleLine: 'false'
+AllowShortLoopsOnASingleLine: 'false'
+AlwaysBreakBeforeMultilineStrings: 'true'
+AlwaysBreakTemplateDeclarations: 'true'
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Linux
+Cpp11BracedListStyle: 'false'
+IncludeBlocks: Preserve
+IndentCaseLabels: 'false'
+IndentPPDirectives: AfterHash
+IndentWidth: '4'
+IndentWrappedFunctionNames: 'true'
+Language: Cpp
+MaxEmptyLinesToKeep: '2'
+NamespaceIndentation: Inner
+PointerAlignment: Left
+SpaceBeforeAssignmentOperators: 'true'
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: 'false'
+SpacesBeforeTrailingComments: '4'
+SpacesInCStyleCastParentheses: 'false'
+SpacesInContainerLiterals: 'false'
+SpacesInParentheses: 'false'
+Standard: Cpp11
+TabWidth: '4'
+UseTab: Never
+
+...
diff --git a/framework/3rd/dmon/.gitignore b/framework/3rd/dmon/.gitignore
new file mode 100755
index 0000000..0308f50
--- /dev/null
+++ b/framework/3rd/dmon/.gitignore
@@ -0,0 +1,72 @@
+# External junk
+.DS_Store
+_ReSharper*
+*.opensdf
+*.sdf
+*.dir
+*.suo
+*.user
+*.bak
+Win32
+Win64
+Debug
+Release
+Profile
+Development
+Obj
+Bin
+Lib
+.tags
+.tags_sorted_by_file
+*.lnk
+ipch
+__pycache__
+Thumbs.db
+.build*
+
+# Gradle
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+/build
+/build-*
+/captures
+
+# assets
+assets/shaders/*
+
+# Generated files
+bin
+docs/Doxyfile
+docs/html
+docs/warnings.txt
+imgui.ini
+install
+*.log
+.vscode/launch.json
+.vscode/c_cpp_properties.json
+shaders_h
+src/rizz/plugin_bundle.h
+src/rizz/plugin_bundle_native.h
+android
+assets-db.json
+compile_commands.json
+examples/assets/shaders/**
+
+# temp
+scripts/generators/fake_libc_include
+temp
+
+# Compiled binaries
+*.so
+*.dylib
+*.dll
+*.a
+*.lib
+*.exe
+.build
+*.fso
+*.vso
+*.pyc
+*.obj
diff --git a/framework/3rd/dmon/README.md b/framework/3rd/dmon/README.md
new file mode 100755
index 0000000..55465de
--- /dev/null
+++ b/framework/3rd/dmon/README.md
@@ -0,0 +1,75 @@
+## dmon
+[@septag](https://twitter.com/septagh)
+
+_dmon_ is a tiny C library that monitors changes in a directory.
+It provides a unified solution to multiple system APIs that exist for each OS. It can also monitor directories recursively.
+
+### Platforms
+- Windows: `ReadDirectoryChangesW` backend. Tested with Windows10 SDK + Visual Studio 2019
+- Linux: `inotify` backend. Tested with gcc-7.4/clang-6, ubuntu 18.04 LTS
+- MacOS: `FSEvents` backend. Tested with MacOS-10.14 clang 10
+
+### Usage
+
+You just have to include the file and use it's functions. It is also compatible with C++ code.
+Backslashes in Windows paths are also converted to '/' for portability.
+
+```c
+#define DMON_IMPL
+#include "dmon.h"
+
+static void watch_callback(dmon_watch_id watch_id, dmon_action action, const char* rootdir,
+ const char* filepath, const char* oldfilepath, void* user)
+{
+ // receive change events. type of event is stored in 'action' variable
+}
+
+int main()
+{
+ dmon_init();
+ dmon_watch("/path/to/directory", watch_callback, DMON_WATCHFLAGS_RECURSIVE, NULL);
+ // wait ...
+ dmon_deinit();
+ return 0;
+}
+```
+
+For more information and how to customize functionality, see [dmon.h](dmon.h)
+
+To build on linux, link with `pthread`:
+```gcc test.c -lpthread -o test```
+
+To build on MacOS, link with `CoreServices` and `CoreFoundation`:
+```clang test.c -framework CoreFoundation -framework CoreServices -lpthread -o test```
+
+[License (BSD 2-clause)](https://github.com/septag/dmon/blob/master/LICENSE)
+--------------------------------------------------------------------------
+
+
+
+
+
+ Copyright 2019 Sepehr Taghdisian. All rights reserved.
+
+ https://github.com/septag/dmon
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/framework/3rd/dmon/dmon.h b/framework/3rd/dmon/dmon.h
new file mode 100755
index 0000000..54928bc
--- /dev/null
+++ b/framework/3rd/dmon/dmon.h
@@ -0,0 +1,1502 @@
+//
+// Copyright 2021 Sepehr Taghdisian (septag@github). All rights reserved.
+// License: https://github.com/septag/dmon#license-bsd-2-clause
+//
+// Portable directory monitoring library
+// watches directories for file or directory changes.
+//
+// clang-format off
+// Usage:
+// define DMON_IMPL and include this file to use it:
+// #define DMON_IMPL
+// #include "dmon.h"
+//
+// dmon_init():
+// Call this once at the start of your program.
+// This will start a low-priority monitoring thread
+// dmon_deinit():
+// Call this when your work with dmon is finished, usually on program terminate
+// This will free resources and stop the monitoring thread
+// dmon_watch:
+// Watch for directories
+// You can watch multiple directories by calling this function multiple times
+// rootdir: root directory to monitor
+// watch_cb: callback function to receive events.
+// NOTE that this function is called from another thread, so you should
+// beware of data races in your application when accessing data within this
+// callback
+// flags: watch flags, see dmon_watch_flags_t
+// user_data: user pointer that is passed to callback function
+// Returns the Id of the watched directory after successful call, or returns Id=0 if error
+// dmon_unwatch:
+// Remove the directory from watch list
+//
+// see test.c for the basic example
+//
+// Configuration:
+// You can customize some low-level functionality like malloc and logging by overriding macros:
+//
+// DMON_MALLOC, DMON_FREE, DMON_REALLOC:
+// define these macros to override memory allocations
+// default is 'malloc', 'free' and 'realloc'
+// DMON_ASSERT:
+// define this to provide your own assert
+// default is 'assert'
+// DMON_LOG_ERROR:
+// define this to provide your own logging mechanism
+// default implementation logs to stdout and breaks the program
+// DMON_LOG_DEBUG
+// define this to provide your own extra debug logging mechanism
+// default implementation logs to stdout in DEBUG and does nothing in other builds
+// DMON_API_DECL, DMON_API_IMPL
+// define these to provide your own API declerations. (for example: static)
+// default is nothing (which is extern in C language )
+// DMON_MAX_PATH
+// Maximum size of path characters
+// default is 260 characters
+// DMON_MAX_WATCHES
+// Maximum number of watch directories
+// default is 64
+//
+// TODO:
+// - DMON_WATCHFLAGS_FOLLOW_SYMLINKS does not resolve files
+// - implement DMON_WATCHFLAGS_OUTOFSCOPE_LINKS
+// - implement DMON_WATCHFLAGS_IGNORE_DIRECTORIES
+//
+// History:
+// 1.0.0 First version. working Win32/Linux backends
+// 1.1.0 MacOS backend
+// 1.1.1 Minor fixes, eliminate gcc/clang warnings with -Wall
+// 1.1.2 Eliminate some win32 dead code
+// 1.1.3 Fixed select not resetting causing high cpu usage on linux
+//
+#ifndef __DMON_H__
+#define __DMON_H__
+
+#include
+#include
+
+#ifndef DMON_API_DECL
+# define DMON_API_DECL
+#endif
+
+#ifndef DMON_API_IMPL
+# define DMON_API_IMPL
+#endif
+
+typedef struct { uint32_t id; } dmon_watch_id;
+
+// Pass these flags to `dmon_watch`
+typedef enum dmon_watch_flags_t {
+ DMON_WATCHFLAGS_RECURSIVE = 0x1, // monitor all child directories
+ DMON_WATCHFLAGS_FOLLOW_SYMLINKS = 0x2, // resolve symlinks (linux only)
+ DMON_WATCHFLAGS_OUTOFSCOPE_LINKS = 0x4, // TODO: not implemented yet
+ DMON_WATCHFLAGS_IGNORE_DIRECTORIES = 0x8 // TODO: not implemented yet
+} dmon_watch_flags;
+
+// Action is what operation performed on the file. this value is provided by watch callback
+typedef enum dmon_action_t {
+ DMON_ACTION_CREATE = 1,
+ DMON_ACTION_DELETE,
+ DMON_ACTION_MODIFY,
+ DMON_ACTION_MOVE
+} dmon_action;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DMON_API_DECL void dmon_init(void);
+DMON_API_DECL void dmon_deinit(void);
+
+DMON_API_DECL dmon_watch_id dmon_watch(const char* rootdir,
+ void (*watch_cb)(dmon_watch_id watch_id, dmon_action action,
+ const char* rootdir, const char* filepath,
+ const char* oldfilepath, void* user),
+ uint32_t flags, void* user_data);
+DMON_API_DECL void dmon_unwatch(dmon_watch_id id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef DMON_IMPL
+
+#define DMON_OS_WINDOWS 0
+#define DMON_OS_MACOS 0
+#define DMON_OS_LINUX 0
+
+#if defined(_WIN32) || defined(_WIN64)
+# undef DMON_OS_WINDOWS
+# define DMON_OS_WINDOWS 1
+#elif defined(__linux__)
+# undef DMON_OS_LINUX
+# define DMON_OS_LINUX 1
+#elif defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+# undef DMON_OS_MACOS
+# define DMON_OS_MACOS __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+#else
+# define DMON_OS 0
+# error "unsupported platform"
+#endif
+
+#if DMON_OS_WINDOWS
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include
+# include
+# ifdef _MSC_VER
+# pragma intrinsic(_InterlockedExchange)
+# endif
+#elif DMON_OS_LINUX
+# ifndef __USE_MISC
+# define __USE_MISC
+# endif
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+#elif DMON_OS_MACOS
+# include
+# include
+# include
+# include
+# include
+#endif
+
+#ifndef DMON_MALLOC
+# include
+# define DMON_MALLOC(size) malloc(size)
+# define DMON_FREE(ptr) free(ptr)
+# define DMON_REALLOC(ptr, size) realloc(ptr, size)
+#endif
+
+#ifndef DMON_ASSERT
+# include
+# define DMON_ASSERT(e) assert(e)
+#endif
+
+#ifndef DMON_LOG_ERROR
+# include
+# define DMON_LOG_ERROR(s) do { puts(s); DMON_ASSERT(0); } while(0)
+#endif
+
+#ifndef DMON_LOG_DEBUG
+# ifndef NDEBUG
+# include
+# define DMON_LOG_DEBUG(s) do { puts(s); } while(0)
+# else
+# define DMON_LOG_DEBUG(s)
+# endif
+#endif
+
+#ifndef DMON_MAX_WATCHES
+# define DMON_MAX_WATCHES 64
+#endif
+
+#ifndef DMON_MAX_PATH
+# define DMON_MAX_PATH 260
+#endif
+
+#define _DMON_UNUSED(x) (void)(x)
+
+#ifndef _DMON_PRIVATE
+# if defined(__GNUC__) || defined(__clang__)
+# define _DMON_PRIVATE __attribute__((unused)) static
+# else
+# define _DMON_PRIVATE static
+# endif
+#endif
+
+#include
+
+#ifndef _DMON_LOG_ERRORF
+# define _DMON_LOG_ERRORF(str, ...) do { char msg[512]; snprintf(msg, sizeof(msg), str, __VA_ARGS__); DMON_LOG_ERROR(msg); } while(0);
+#endif
+
+#ifndef _DMON_LOG_DEBUGF
+# define _DMON_LOG_DEBUGF(str, ...) do { char msg[512]; snprintf(msg, sizeof(msg), str, __VA_ARGS__); DMON_LOG_DEBUG(msg); } while(0);
+#endif
+
+#ifndef dmon__min
+# define dmon__min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef dmon__max
+# define dmon__max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef dmon__swap
+# define dmon__swap(a, b, _type) \
+ do { \
+ _type tmp = a; \
+ a = b; \
+ b = tmp; \
+ } while (0)
+#endif
+
+#ifndef dmon__make_id
+# ifdef __cplusplus
+# define dmon__make_id(id) {id}
+# else
+# define dmon__make_id(id) (dmon_watch_id) {id}
+# endif
+#endif // dmon__make_id
+
+_DMON_PRIVATE bool dmon__isrange(char ch, char from, char to)
+{
+ return (uint8_t)(ch - from) <= (uint8_t)(to - from);
+}
+
+_DMON_PRIVATE bool dmon__isupperchar(char ch)
+{
+ return dmon__isrange(ch, 'A', 'Z');
+}
+
+_DMON_PRIVATE char dmon__tolowerchar(char ch)
+{
+ return ch + (dmon__isupperchar(ch) ? 0x20 : 0);
+}
+
+_DMON_PRIVATE char* dmon__tolower(char* dst, int dst_sz, const char* str)
+{
+ int offset = 0;
+ int dst_max = dst_sz - 1;
+ while (*str && offset < dst_max) {
+ dst[offset++] = dmon__tolowerchar(*str);
+ ++str;
+ }
+ dst[offset] = '\0';
+ return dst;
+}
+
+_DMON_PRIVATE char* dmon__strcpy(char* dst, int dst_sz, const char* src)
+{
+ DMON_ASSERT(dst);
+ DMON_ASSERT(src);
+
+ const int32_t len = (int32_t)strlen(src);
+ const int32_t _max = dst_sz - 1;
+ const int32_t num = (len < _max ? len : _max);
+ memcpy(dst, src, num);
+ dst[num] = '\0';
+
+ return dst;
+}
+
+_DMON_PRIVATE char* dmon__unixpath(char* dst, int size, const char* path)
+{
+ size_t len = strlen(path);
+ len = dmon__min(len, (size_t)size - 1);
+
+ for (size_t i = 0; i < len; i++) {
+ if (path[i] != '\\')
+ dst[i] = path[i];
+ else
+ dst[i] = '/';
+ }
+ dst[len] = '\0';
+ return dst;
+}
+
+#if DMON_OS_LINUX || DMON_OS_MACOS
+_DMON_PRIVATE char* dmon__strcat(char* dst, int dst_sz, const char* src)
+{
+ int len = (int)strlen(dst);
+ return dmon__strcpy(dst + len, dst_sz - len, src);
+}
+#endif // DMON_OS_LINUX || DMON_OS_MACOS
+
+// stretchy buffer: https://github.com/nothings/stb/blob/master/stretchy_buffer.h
+#define stb_sb_free(a) ((a) ? DMON_FREE(stb__sbraw(a)),0 : 0)
+#define stb_sb_push(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v))
+#define stb_sb_count(a) ((a) ? stb__sbn(a) : 0)
+#define stb_sb_add(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)])
+#define stb_sb_last(a) ((a)[stb__sbn(a)-1])
+#define stb_sb_reset(a) ((a) ? (stb__sbn(a) = 0) : 0)
+
+#define stb__sbraw(a) ((int *) (a) - 2)
+#define stb__sbm(a) stb__sbraw(a)[0]
+#define stb__sbn(a) stb__sbraw(a)[1]
+
+#define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a))
+#define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0)
+#define stb__sbgrow(a,n) (*((void **)&(a)) = stb__sbgrowf((a), (n), sizeof(*(a))))
+
+static void * stb__sbgrowf(void *arr, int increment, int itemsize)
+{
+ int dbl_cur = arr ? 2*stb__sbm(arr) : 0;
+ int min_needed = stb_sb_count(arr) + increment;
+ int m = dbl_cur > min_needed ? dbl_cur : min_needed;
+ int *p = (int *) DMON_REALLOC(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2);
+ if (p) {
+ if (!arr)
+ p[1] = 0;
+ p[0] = m;
+ return p+2;
+ } else {
+ return (void *) (2*sizeof(int)); // try to force a NULL pointer exception later
+ }
+}
+
+// watcher callback (same as dmon.h's decleration)
+typedef void (dmon__watch_cb)(dmon_watch_id, dmon_action, const char*, const char*, const char*, void*);
+
+#if DMON_OS_WINDOWS
+// IOCP (windows)
+#ifdef UNICODE
+# define _DMON_WINAPI_STR(name, size) wchar_t _##name[size]; MultiByteToWideChar(CP_UTF8, 0, name, -1, _##name, size)
+#else
+# define _DMON_WINAPI_STR(name, size) const char* _##name = name
+#endif
+
+typedef struct dmon__win32_event {
+ char filepath[DMON_MAX_PATH];
+ DWORD action;
+ dmon_watch_id watch_id;
+ bool skip;
+} dmon__win32_event;
+
+typedef struct dmon__watch_state {
+ dmon_watch_id id;
+ OVERLAPPED overlapped;
+ HANDLE dir_handle;
+ uint8_t buffer[64512]; // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx
+ DWORD notify_filter;
+ dmon__watch_cb* watch_cb;
+ uint32_t watch_flags;
+ void* user_data;
+ char rootdir[DMON_MAX_PATH];
+ char old_filepath[DMON_MAX_PATH];
+} dmon__watch_state;
+
+typedef struct dmon__state {
+ int num_watches;
+ dmon__watch_state watches[DMON_MAX_WATCHES];
+ HANDLE thread_handle;
+ CRITICAL_SECTION mutex;
+ volatile LONG modify_watches;
+ dmon__win32_event* events;
+ bool quit;
+} dmon__state;
+
+static bool _dmon_init;
+static dmon__state _dmon;
+
+// clang-format on
+
+_DMON_PRIVATE bool dmon__refresh_watch(dmon__watch_state* watch)
+{
+ return ReadDirectoryChangesW(watch->dir_handle, watch->buffer, sizeof(watch->buffer),
+ (watch->watch_flags & DMON_WATCHFLAGS_RECURSIVE) ? TRUE : FALSE,
+ watch->notify_filter, NULL, &watch->overlapped, NULL) != 0;
+}
+
+_DMON_PRIVATE void dmon__unwatch(dmon__watch_state* watch)
+{
+ CancelIo(watch->dir_handle);
+ CloseHandle(watch->overlapped.hEvent);
+ CloseHandle(watch->dir_handle);
+ memset(watch, 0x0, sizeof(dmon__watch_state));
+}
+
+_DMON_PRIVATE void dmon__win32_process_events(void)
+{
+ for (int i = 0, c = stb_sb_count(_dmon.events); i < c; i++) {
+ dmon__win32_event* ev = &_dmon.events[i];
+ if (ev->skip) {
+ continue;
+ }
+
+ if (ev->action == FILE_ACTION_MODIFIED || ev->action == FILE_ACTION_ADDED) {
+ // remove duplicate modifies on a single file
+ for (int j = i + 1; j < c; j++) {
+ dmon__win32_event* check_ev = &_dmon.events[j];
+ if (check_ev->action == FILE_ACTION_MODIFIED &&
+ strcmp(ev->filepath, check_ev->filepath) == 0) {
+ check_ev->skip = true;
+ }
+ }
+ }
+ }
+
+ // trigger user callbacks
+ for (int i = 0, c = stb_sb_count(_dmon.events); i < c; i++) {
+ dmon__win32_event* ev = &_dmon.events[i];
+ if (ev->skip) {
+ continue;
+ }
+ dmon__watch_state* watch = &_dmon.watches[ev->watch_id.id - 1];
+
+ if(watch == NULL || watch->watch_cb == NULL) {
+ continue;
+ }
+
+ switch (ev->action) {
+ case FILE_ACTION_ADDED:
+ watch->watch_cb(ev->watch_id, DMON_ACTION_CREATE, watch->rootdir, ev->filepath, NULL,
+ watch->user_data);
+ break;
+ case FILE_ACTION_MODIFIED:
+ watch->watch_cb(ev->watch_id, DMON_ACTION_MODIFY, watch->rootdir, ev->filepath, NULL,
+ watch->user_data);
+ break;
+ case FILE_ACTION_RENAMED_OLD_NAME: {
+ // find the first occurance of the NEW_NAME
+ // this is somewhat API flaw that we have no reference for relating old and new files
+ for (int j = i + 1; j < c; j++) {
+ dmon__win32_event* check_ev = &_dmon.events[j];
+ if (check_ev->action == FILE_ACTION_RENAMED_NEW_NAME) {
+ watch->watch_cb(check_ev->watch_id, DMON_ACTION_MOVE, watch->rootdir,
+ check_ev->filepath, ev->filepath, watch->user_data);
+ break;
+ }
+ }
+ } break;
+ case FILE_ACTION_REMOVED:
+ watch->watch_cb(ev->watch_id, DMON_ACTION_DELETE, watch->rootdir, ev->filepath, NULL,
+ watch->user_data);
+ break;
+ }
+ }
+ stb_sb_reset(_dmon.events);
+}
+
+_DMON_PRIVATE DWORD WINAPI dmon__thread(LPVOID arg)
+{
+ _DMON_UNUSED(arg);
+ HANDLE wait_handles[DMON_MAX_WATCHES];
+
+ SYSTEMTIME starttm;
+ GetSystemTime(&starttm);
+ uint64_t msecs_elapsed = 0;
+
+ while (!_dmon.quit) {
+ if (_dmon.modify_watches || !TryEnterCriticalSection(&_dmon.mutex)) {
+ Sleep(10);
+ continue;
+ }
+
+ if (_dmon.num_watches == 0) {
+ Sleep(10);
+ LeaveCriticalSection(&_dmon.mutex);
+ continue;
+ }
+
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__watch_state* watch = &_dmon.watches[i];
+ wait_handles[i] = watch->overlapped.hEvent;
+ }
+
+ DWORD wait_result = WaitForMultipleObjects(_dmon.num_watches, wait_handles, FALSE, 10);
+ DMON_ASSERT(wait_result != WAIT_FAILED);
+ if (wait_result != WAIT_TIMEOUT) {
+ dmon__watch_state* watch = &_dmon.watches[wait_result - WAIT_OBJECT_0];
+ DMON_ASSERT(HasOverlappedIoCompleted(&watch->overlapped));
+
+ DWORD bytes;
+ if (GetOverlappedResult(watch->dir_handle, &watch->overlapped, &bytes, FALSE)) {
+ char filepath[DMON_MAX_PATH];
+ PFILE_NOTIFY_INFORMATION notify;
+ size_t offset = 0;
+
+ if (bytes == 0) {
+ dmon__refresh_watch(watch);
+ LeaveCriticalSection(&_dmon.mutex);
+ continue;
+ }
+
+ do {
+ notify = (PFILE_NOTIFY_INFORMATION)&watch->buffer[offset];
+
+ int count = WideCharToMultiByte(CP_UTF8, 0, notify->FileName,
+ notify->FileNameLength / sizeof(WCHAR),
+ filepath, DMON_MAX_PATH - 1, NULL, NULL);
+ filepath[count] = TEXT('\0');
+ dmon__unixpath(filepath, sizeof(filepath), filepath);
+
+ // TODO: ignore directories if flag is set
+
+ if (stb_sb_count(_dmon.events) == 0) {
+ msecs_elapsed = 0;
+ }
+ dmon__win32_event wev = { { 0 }, notify->Action, watch->id, false };
+ dmon__strcpy(wev.filepath, sizeof(wev.filepath), filepath);
+ stb_sb_push(_dmon.events, wev);
+
+ offset += notify->NextEntryOffset;
+ } while (notify->NextEntryOffset > 0);
+
+ if (!_dmon.quit) {
+ dmon__refresh_watch(watch);
+ }
+ }
+ } // if (WaitForMultipleObjects)
+
+ SYSTEMTIME tm;
+ GetSystemTime(&tm);
+ LONG dt =
+ (tm.wSecond - starttm.wSecond) * 1000 + (tm.wMilliseconds - starttm.wMilliseconds);
+ starttm = tm;
+ msecs_elapsed += dt;
+ if (msecs_elapsed > 100 && stb_sb_count(_dmon.events) > 0) {
+ dmon__win32_process_events();
+ msecs_elapsed = 0;
+ }
+
+ LeaveCriticalSection(&_dmon.mutex);
+ }
+ return 0;
+}
+
+
+DMON_API_IMPL void dmon_init(void)
+{
+ DMON_ASSERT(!_dmon_init);
+ InitializeCriticalSection(&_dmon.mutex);
+
+ _dmon.thread_handle =
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)dmon__thread, NULL, 0, NULL);
+ DMON_ASSERT(_dmon.thread_handle);
+ _dmon_init = true;
+}
+
+
+DMON_API_IMPL void dmon_deinit(void)
+{
+ DMON_ASSERT(_dmon_init);
+ _dmon.quit = true;
+ if (_dmon.thread_handle != INVALID_HANDLE_VALUE) {
+ WaitForSingleObject(_dmon.thread_handle, INFINITE);
+ CloseHandle(_dmon.thread_handle);
+ }
+
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__unwatch(&_dmon.watches[i]);
+ }
+
+ DeleteCriticalSection(&_dmon.mutex);
+ stb_sb_free(_dmon.events);
+ _dmon_init = false;
+}
+
+DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir,
+ void (*watch_cb)(dmon_watch_id watch_id, dmon_action action,
+ const char* dirname, const char* filename,
+ const char* oldname, void* user),
+ uint32_t flags, void* user_data)
+{
+ DMON_ASSERT(watch_cb);
+ DMON_ASSERT(rootdir && rootdir[0]);
+
+ _InterlockedExchange(&_dmon.modify_watches, 1);
+ EnterCriticalSection(&_dmon.mutex);
+
+ DMON_ASSERT(_dmon.num_watches < DMON_MAX_WATCHES);
+
+ uint32_t id = ++_dmon.num_watches;
+ dmon__watch_state* watch = &_dmon.watches[id - 1];
+ watch->id = dmon__make_id(id);
+ watch->watch_flags = flags;
+ watch->watch_cb = watch_cb;
+ watch->user_data = user_data;
+
+ dmon__strcpy(watch->rootdir, sizeof(watch->rootdir) - 1, rootdir);
+ dmon__unixpath(watch->rootdir, sizeof(watch->rootdir), rootdir);
+ size_t rootdir_len = strlen(watch->rootdir);
+ if (watch->rootdir[rootdir_len - 1] != '/') {
+ watch->rootdir[rootdir_len] = '/';
+ watch->rootdir[rootdir_len + 1] = '\0';
+ }
+
+ _DMON_WINAPI_STR(rootdir, DMON_MAX_PATH);
+ watch->dir_handle =
+ CreateFile(_rootdir, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
+ if (watch->dir_handle != INVALID_HANDLE_VALUE) {
+ watch->notify_filter = FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_SIZE;
+ watch->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ DMON_ASSERT(watch->overlapped.hEvent != INVALID_HANDLE_VALUE);
+
+ if (!dmon__refresh_watch(watch)) {
+ dmon__unwatch(watch);
+ DMON_LOG_ERROR("ReadDirectoryChanges failed");
+ LeaveCriticalSection(&_dmon.mutex);
+ _InterlockedExchange(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+ } else {
+ _DMON_LOG_ERRORF("Could not open: %s", rootdir);
+ LeaveCriticalSection(&_dmon.mutex);
+ _InterlockedExchange(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+
+ LeaveCriticalSection(&_dmon.mutex);
+ _InterlockedExchange(&_dmon.modify_watches, 0);
+ return dmon__make_id(id);
+}
+
+DMON_API_IMPL void dmon_unwatch(dmon_watch_id id)
+{
+ DMON_ASSERT(id.id > 0);
+
+ _InterlockedExchange(&_dmon.modify_watches, 1);
+ EnterCriticalSection(&_dmon.mutex);
+
+ int index = id.id - 1;
+ DMON_ASSERT(index < _dmon.num_watches);
+
+ dmon__unwatch(&_dmon.watches[index]);
+ if (index != _dmon.num_watches - 1) {
+ dmon__swap(_dmon.watches[index], _dmon.watches[_dmon.num_watches - 1], dmon__watch_state);
+ }
+ --_dmon.num_watches;
+
+ LeaveCriticalSection(&_dmon.mutex);
+ _InterlockedExchange(&_dmon.modify_watches, 0);
+}
+
+// clang-format off
+#elif DMON_OS_LINUX
+// inotify linux backend
+#define _DMON_TEMP_BUFFSIZE ((sizeof(struct inotify_event) + PATH_MAX) * 1024)
+
+typedef struct dmon__watch_subdir {
+ char rootdir[DMON_MAX_PATH];
+} dmon__watch_subdir;
+
+typedef struct dmon__inotify_event {
+ char filepath[DMON_MAX_PATH];
+ uint32_t mask;
+ uint32_t cookie;
+ dmon_watch_id watch_id;
+ bool skip;
+} dmon__inotify_event;
+
+typedef struct dmon__watch_state {
+ dmon_watch_id id;
+ int fd;
+ uint32_t watch_flags;
+ dmon__watch_cb* watch_cb;
+ void* user_data;
+ char rootdir[DMON_MAX_PATH];
+ dmon__watch_subdir* subdirs;
+ int* wds;
+} dmon__watch_state;
+
+typedef struct dmon__state {
+ dmon__watch_state watches[DMON_MAX_WATCHES];
+ dmon__inotify_event* events;
+ int num_watches;
+ volatile int modify_watches;
+ pthread_t thread_handle;
+ pthread_mutex_t mutex;
+ bool quit;
+} dmon__state;
+
+static bool _dmon_init;
+static dmon__state _dmon;
+// clang-format on
+
+_DMON_PRIVATE void dmon__watch_recursive(const char* dirname, int fd, uint32_t mask,
+ bool followlinks, dmon__watch_state* watch)
+{
+ struct dirent* entry;
+ DIR* dir = opendir(dirname);
+ DMON_ASSERT(dir);
+
+ char watchdir[DMON_MAX_PATH];
+
+ while ((entry = readdir(dir)) != NULL) {
+ bool entry_valid = false;
+ if (entry->d_type == DT_DIR) {
+ if (strcmp(entry->d_name, "..") != 0 && strcmp(entry->d_name, ".") != 0) {
+ dmon__strcpy(watchdir, sizeof(watchdir), dirname);
+ dmon__strcat(watchdir, sizeof(watchdir), entry->d_name);
+ entry_valid = true;
+ }
+ } else if (followlinks && entry->d_type == DT_LNK) {
+ char linkpath[PATH_MAX];
+ dmon__strcpy(watchdir, sizeof(watchdir), dirname);
+ dmon__strcat(watchdir, sizeof(watchdir), entry->d_name);
+ char* r = realpath(watchdir, linkpath);
+ _DMON_UNUSED(r);
+ DMON_ASSERT(r);
+ dmon__strcpy(watchdir, sizeof(watchdir), linkpath);
+ entry_valid = true;
+ }
+
+ // add sub-directory to watch dirs
+ if (entry_valid) {
+ int watchdir_len = strlen(watchdir);
+ if (watchdir[watchdir_len - 1] != '/') {
+ watchdir[watchdir_len] = '/';
+ watchdir[watchdir_len + 1] = '\0';
+ }
+ int wd = inotify_add_watch(fd, watchdir, mask);
+ _DMON_UNUSED(wd);
+ DMON_ASSERT(wd != -1);
+
+ dmon__watch_subdir subdir;
+ dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir);
+ stb_sb_push(watch->subdirs, subdir);
+ stb_sb_push(watch->wds, wd);
+
+ // recurse
+ dmon__watch_recursive(watchdir, fd, mask, followlinks, watch);
+ }
+ }
+ closedir(dir);
+}
+
+_DMON_PRIVATE void dmon__inotify_process_events(void)
+{
+ for (int i = 0, c = stb_sb_count(_dmon.events); i < c; i++) {
+ dmon__inotify_event* ev = &_dmon.events[i];
+ if (ev->skip) {
+ continue;
+ }
+
+ // remove redundant modify events on a single file
+ if (ev->mask == IN_MODIFY) {
+ for (int j = i + 1; j < c; j++) {
+ dmon__inotify_event* check_ev = &_dmon.events[j];
+ if (check_ev->mask == IN_MODIFY && strcmp(ev->filepath, check_ev->filepath) == 0) {
+ ev->skip = true;
+ break;
+ }
+ }
+ } else if (ev->mask == IN_CREATE) {
+ bool loop_break = false;
+ for (int j = i + 1; j < c && !loop_break; j++) {
+ dmon__inotify_event* check_ev = &_dmon.events[j];
+ if (check_ev->mask == IN_MOVED_FROM &&
+ strcmp(ev->filepath, check_ev->filepath) == 0) {
+ // there is a case where some programs (like gedit):
+ // when we save, it creates a temp file, and moves it to the file being modified
+ // search for these cases and remove all of them
+ for (int k = j + 1; k < c; k++) {
+ dmon__inotify_event* third_ev = &_dmon.events[k];
+ if (third_ev->mask == IN_MOVED_TO && check_ev->cookie == third_ev->cookie) {
+ third_ev->mask = IN_MODIFY; // change to modified
+ ev->skip = check_ev->skip = true;
+ loop_break = true;
+ break;
+ }
+ }
+ } else if (check_ev->mask == IN_MODIFY && strcmp(ev->filepath, check_ev->filepath) == 0) {
+ // Another case is that file is copied. CREATE and MODIFY happens sequentially
+ // so we ignore MODIFY event
+ check_ev->skip = true;
+ }
+ }
+ } else if (ev->mask == IN_MOVED_FROM) {
+ bool move_valid = false;
+ for (int j = i + 1; j < c; j++) {
+ dmon__inotify_event* check_ev = &_dmon.events[j];
+ if (check_ev->mask == IN_MOVED_TO && ev->cookie == check_ev->cookie) {
+ move_valid = true;
+ break;
+ }
+ }
+
+ // in some environments like nautilus file explorer:
+ // when a file is deleted, it is moved to recycle bin
+ // so if the destination of the move is not valid, it's probably DELETE
+ if (!move_valid) {
+ ev->mask = IN_DELETE;
+ }
+ } else if (ev->mask == IN_MOVED_TO) {
+ bool move_valid = false;
+ for (int j = 0; j < i; j++) {
+ dmon__inotify_event* check_ev = &_dmon.events[j];
+ if (check_ev->mask == IN_MOVED_FROM && ev->cookie == check_ev->cookie) {
+ move_valid = true;
+ break;
+ }
+ }
+
+ // in some environments like nautilus file explorer:
+ // when a file is deleted, it is moved to recycle bin, on undo it is moved back it
+ // so if the destination of the move is not valid, it's probably CREATE
+ if (!move_valid) {
+ ev->mask = IN_CREATE;
+ }
+ }
+ }
+
+ // trigger user callbacks
+ for (int i = 0, c = stb_sb_count(_dmon.events); i < c; i++) {
+ dmon__inotify_event* ev = &_dmon.events[i];
+ if (ev->skip) {
+ continue;
+ }
+ dmon__watch_state* watch = &_dmon.watches[ev->watch_id.id - 1];
+
+ if(watch == NULL || watch->watch_cb == NULL) {
+ continue;
+ }
+
+ switch (ev->mask) {
+ case IN_CREATE:
+ watch->watch_cb(ev->watch_id, DMON_ACTION_CREATE, watch->rootdir, ev->filepath, NULL, watch->user_data);
+ break;
+ case IN_MODIFY:
+ watch->watch_cb(ev->watch_id, DMON_ACTION_MODIFY, watch->rootdir, ev->filepath, NULL, watch->user_data);
+ break;
+ case IN_MOVED_FROM: {
+ for (int j = i + 1; j < c; j++) {
+ dmon__inotify_event* check_ev = &_dmon.events[j];
+ if (check_ev->mask == IN_MOVED_TO && ev->cookie == check_ev->cookie) {
+ watch->watch_cb(check_ev->watch_id, DMON_ACTION_MOVE, watch->rootdir,
+ check_ev->filepath, ev->filepath, watch->user_data);
+ break;
+ }
+ }
+ } break;
+ case IN_DELETE:
+ watch->watch_cb(ev->watch_id, DMON_ACTION_DELETE, watch->rootdir, ev->filepath, NULL, watch->user_data);
+ break;
+ }
+ }
+
+
+ stb_sb_reset(_dmon.events);
+}
+
+static void* dmon__thread(void* arg)
+{
+ _DMON_UNUSED(arg);
+
+ static uint8_t buff[_DMON_TEMP_BUFFSIZE];
+ struct timespec req = { (time_t)10 / 1000, (long)(10 * 1000000) };
+ struct timespec rem = { 0, 0 };
+ struct timeval timeout;
+ uint64_t usecs_elapsed = 0;
+
+ struct timeval starttm;
+ gettimeofday(&starttm, 0);
+
+ while (!_dmon.quit) {
+
+ if (_dmon.modify_watches || pthread_mutex_trylock(&_dmon.mutex) != 0) {
+ nanosleep(&req, &rem);
+ continue;
+ }
+
+ if (_dmon.num_watches == 0) {
+ nanosleep(&req, &rem);
+ pthread_mutex_unlock(&_dmon.mutex);
+ continue;
+ }
+
+ // Create read FD set
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__watch_state* watch = &_dmon.watches[i];
+ FD_SET(watch->fd, &rfds);
+ }
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+ if (select(FD_SETSIZE, &rfds, NULL, NULL, &timeout)) {
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__watch_state* watch = &_dmon.watches[i];
+ if (FD_ISSET(watch->fd, &rfds)) {
+ ssize_t offset = 0;
+ ssize_t len = read(watch->fd, buff, _DMON_TEMP_BUFFSIZE);
+ if (len <= 0) {
+ continue;
+ }
+
+ while (offset < len) {
+ struct inotify_event* iev = (struct inotify_event*)&buff[offset];
+
+ char filepath[DMON_MAX_PATH];
+ dmon__strcpy(filepath, sizeof(filepath), iev->name);
+
+ // TODO: ignore directories if flag is set
+
+ if (stb_sb_count(_dmon.events) == 0) {
+ usecs_elapsed = 0;
+ }
+ dmon__inotify_event dev = { { 0 }, iev->mask, iev->cookie, watch->id, false };
+ dmon__strcpy(dev.filepath, sizeof(dev.filepath), filepath);
+ stb_sb_push(_dmon.events, dev);
+
+ offset += sizeof(struct inotify_event) + iev->len;
+ }
+ }
+ }
+ }
+
+ struct timeval tm;
+ gettimeofday(&tm, 0);
+ long dt = (tm.tv_sec - starttm.tv_sec) * 1000000 + tm.tv_usec - starttm.tv_usec;
+ starttm = tm;
+ usecs_elapsed += dt;
+ if (usecs_elapsed > 100000 && stb_sb_count(_dmon.events) > 0) {
+ dmon__inotify_process_events();
+ usecs_elapsed = 0;
+ }
+
+ pthread_mutex_unlock(&_dmon.mutex);
+ }
+ return 0x0;
+}
+
+_DMON_PRIVATE void dmon__unwatch(dmon__watch_state* watch)
+{
+ close(watch->fd);
+ stb_sb_free(watch->subdirs);
+ stb_sb_free(watch->wds);
+ memset(watch, 0x0, sizeof(dmon__watch_state));
+}
+
+DMON_API_IMPL void dmon_init(void)
+{
+ DMON_ASSERT(!_dmon_init);
+ pthread_mutex_init(&_dmon.mutex, NULL);
+
+ int r = pthread_create(&_dmon.thread_handle, NULL, dmon__thread, NULL);
+ _DMON_UNUSED(r);
+ DMON_ASSERT(r == 0 && "pthread_create failed");
+ _dmon_init = true;
+}
+
+DMON_API_IMPL void dmon_deinit(void)
+{
+ DMON_ASSERT(_dmon_init);
+ _dmon.quit = true;
+ pthread_join(_dmon.thread_handle, NULL);
+
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__unwatch(&_dmon.watches[i]);
+ }
+
+ pthread_mutex_destroy(&_dmon.mutex);
+ stb_sb_free(_dmon.events);
+ _dmon_init = false;
+}
+
+DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir,
+ void (*watch_cb)(dmon_watch_id watch_id, dmon_action action,
+ const char* dirname, const char* filename,
+ const char* oldname, void* user),
+ uint32_t flags, void* user_data)
+{
+ DMON_ASSERT(watch_cb);
+ DMON_ASSERT(rootdir && rootdir[0]);
+
+ __sync_lock_test_and_set(&_dmon.modify_watches, 1);
+ pthread_mutex_lock(&_dmon.mutex);
+
+ DMON_ASSERT(_dmon.num_watches < DMON_MAX_WATCHES);
+
+ uint32_t id = ++_dmon.num_watches;
+ dmon__watch_state* watch = &_dmon.watches[id - 1];
+ watch->id = dmon__make_id(id);
+ watch->watch_flags = flags;
+ watch->watch_cb = watch_cb;
+ watch->user_data = user_data;
+
+ struct stat root_st;
+ if (stat(rootdir, &root_st) != 0 || !S_ISDIR(root_st.st_mode) ||
+ (root_st.st_mode & S_IRUSR) != S_IRUSR) {
+ _DMON_LOG_ERRORF("Could not open/read directory: %s", rootdir);
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+
+
+ if (S_ISLNK(root_st.st_mode)) {
+ if (flags & DMON_WATCHFLAGS_FOLLOW_SYMLINKS) {
+ char linkpath[PATH_MAX];
+ char* r = realpath(rootdir, linkpath);
+ _DMON_UNUSED(r);
+ DMON_ASSERT(r);
+
+ dmon__strcpy(watch->rootdir, sizeof(watch->rootdir) - 1, linkpath);
+ } else {
+ _DMON_LOG_ERRORF("symlinks are unsupported: %s. use DMON_WATCHFLAGS_FOLLOW_SYMLINKS",
+ rootdir);
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+ } else {
+ dmon__strcpy(watch->rootdir, sizeof(watch->rootdir) - 1, rootdir);
+ }
+
+ // add trailing slash
+ int rootdir_len = strlen(watch->rootdir);
+ if (watch->rootdir[rootdir_len - 1] != '/') {
+ watch->rootdir[rootdir_len] = '/';
+ watch->rootdir[rootdir_len + 1] = '\0';
+ }
+
+ watch->fd = inotify_init();
+ if (watch->fd < -1) {
+ DMON_LOG_ERROR("could not create inotify instance");
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+
+ uint32_t inotify_mask = IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE | IN_MODIFY;
+ int wd = inotify_add_watch(watch->fd, watch->rootdir, inotify_mask);
+ if (wd < 0) {
+ _DMON_LOG_ERRORF("watch failed: %s", watch->rootdir);
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+ dmon__watch_subdir subdir;
+ dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watch->rootdir);
+ stb_sb_push(watch->subdirs, subdir);
+ stb_sb_push(watch->wds, wd);
+
+ // recursive mode: enumarate all child directories and add them to watch
+ if (flags & DMON_WATCHFLAGS_RECURSIVE) {
+ dmon__watch_recursive(watch->rootdir, watch->fd, inotify_mask,
+ (flags & DMON_WATCHFLAGS_FOLLOW_SYMLINKS) ? true : false, watch);
+ }
+
+
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(id);
+}
+
+DMON_API_IMPL void dmon_unwatch(dmon_watch_id id)
+{
+ DMON_ASSERT(id.id > 0);
+
+ __sync_lock_test_and_set(&_dmon.modify_watches, 1);
+ pthread_mutex_lock(&_dmon.mutex);
+
+ int index = id.id - 1;
+ DMON_ASSERT(index < _dmon.num_watches);
+
+ dmon__unwatch(&_dmon.watches[index]);
+ if (index != _dmon.num_watches - 1) {
+ dmon__swap(_dmon.watches[index], _dmon.watches[_dmon.num_watches - 1], dmon__watch_state);
+ }
+ --_dmon.num_watches;
+
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+}
+// clang-format off
+#elif DMON_OS_MACOS
+// FSEvents MacOS backend
+typedef struct dmon__fsevent_event {
+ char filepath[DMON_MAX_PATH];
+ uint64_t event_id;
+ long event_flags;
+ dmon_watch_id watch_id;
+ bool skip;
+ bool move_valid;
+} dmon__fsevent_event;
+
+typedef struct dmon__watch_state {
+ dmon_watch_id id;
+ uint32_t watch_flags;
+ FSEventStreamRef fsev_stream_ref;
+ dmon__watch_cb* watch_cb;
+ void* user_data;
+ char rootdir[DMON_MAX_PATH];
+ bool init;
+} dmon__watch_state;
+
+typedef struct dmon__state {
+ dmon__watch_state watches[DMON_MAX_WATCHES];
+ dmon__fsevent_event* events;
+ int num_watches;
+ volatile int modify_watches;
+ pthread_t thread_handle;
+ dispatch_semaphore_t thread_sem;
+ pthread_mutex_t mutex;
+ CFRunLoopRef cf_loop_ref;
+ CFAllocatorRef cf_alloc_ref;
+ bool quit;
+} dmon__state;
+
+union dmon__cast_userdata {
+ void* ptr;
+ uint32_t id;
+};
+
+static bool _dmon_init;
+static dmon__state _dmon;
+// clang-format on
+
+_DMON_PRIVATE void* dmon__cf_malloc(CFIndex size, CFOptionFlags hints, void* info)
+{
+ _DMON_UNUSED(hints);
+ _DMON_UNUSED(info);
+ return DMON_MALLOC(size);
+}
+
+_DMON_PRIVATE void dmon__cf_free(void* ptr, void* info)
+{
+ _DMON_UNUSED(info);
+ DMON_FREE(ptr);
+}
+
+_DMON_PRIVATE void* dmon__cf_realloc(void* ptr, CFIndex newsize, CFOptionFlags hints, void* info)
+{
+ _DMON_UNUSED(hints);
+ _DMON_UNUSED(info);
+ return DMON_REALLOC(ptr, (size_t)newsize);
+}
+
+_DMON_PRIVATE void dmon__fsevent_process_events(void)
+{
+ for (int i = 0, c = stb_sb_count(_dmon.events); i < c; i++) {
+ dmon__fsevent_event* ev = &_dmon.events[i];
+ if (ev->skip) {
+ continue;
+ }
+
+ // remove redundant modify events on a single file
+ if (ev->event_flags & kFSEventStreamEventFlagItemModified) {
+ for (int j = i + 1; j < c; j++) {
+ dmon__fsevent_event* check_ev = &_dmon.events[j];
+ if ((check_ev->event_flags & kFSEventStreamEventFlagItemModified) &&
+ strcmp(ev->filepath, check_ev->filepath) == 0) {
+ ev->skip = true;
+ break;
+ }
+ }
+ } else if ((ev->event_flags & kFSEventStreamEventFlagItemRenamed) && !ev->move_valid) {
+ for (int j = i + 1; j < c; j++) {
+ dmon__fsevent_event* check_ev = &_dmon.events[j];
+ if ((check_ev->event_flags & kFSEventStreamEventFlagItemRenamed) &&
+ check_ev->event_id == (ev->event_id + 1)) {
+ ev->move_valid = check_ev->move_valid = true;
+ break;
+ }
+ }
+
+ // in some environments like finder file explorer:
+ // when a file is deleted, it is moved to recycle bin
+ // so if the destination of the move is not valid, it's probably DELETE or CREATE
+ // decide CREATE if file exists
+ if (!ev->move_valid) {
+ ev->event_flags &= ~kFSEventStreamEventFlagItemRenamed;
+
+ char abs_filepath[DMON_MAX_PATH];
+ dmon__watch_state* watch = &_dmon.watches[ev->watch_id.id-1];
+ dmon__strcpy(abs_filepath, sizeof(abs_filepath), watch->rootdir);
+ dmon__strcat(abs_filepath, sizeof(abs_filepath), ev->filepath);
+
+ struct stat root_st;
+ if (stat(abs_filepath, &root_st) != 0) {
+ ev->event_flags |= kFSEventStreamEventFlagItemRemoved;
+ } else {
+ ev->event_flags |= kFSEventStreamEventFlagItemCreated;
+ }
+ }
+ }
+ }
+
+ // trigger user callbacks
+ for (int i = 0, c = stb_sb_count(_dmon.events); i < c; i++) {
+ dmon__fsevent_event* ev = &_dmon.events[i];
+ if (ev->skip) {
+ continue;
+ }
+ dmon__watch_state* watch = &_dmon.watches[ev->watch_id.id - 1];
+
+ if(watch == NULL || watch->watch_cb == NULL) {
+ continue;
+ }
+
+ if (ev->event_flags & kFSEventStreamEventFlagItemCreated) {
+ watch->watch_cb(ev->watch_id, DMON_ACTION_CREATE, watch->rootdir, ev->filepath, NULL,
+ watch->user_data);
+ } else if (ev->event_flags & kFSEventStreamEventFlagItemModified) {
+ watch->watch_cb(ev->watch_id, DMON_ACTION_MODIFY, watch->rootdir, ev->filepath, NULL,
+ watch->user_data);
+ } else if (ev->event_flags & kFSEventStreamEventFlagItemRenamed) {
+ for (int j = i + 1; j < c; j++) {
+ dmon__fsevent_event* check_ev = &_dmon.events[j];
+ if (check_ev->event_flags & kFSEventStreamEventFlagItemRenamed) {
+ watch->watch_cb(check_ev->watch_id, DMON_ACTION_MOVE, watch->rootdir,
+ check_ev->filepath, ev->filepath, watch->user_data);
+ break;
+ }
+ }
+ } else if (ev->event_flags & kFSEventStreamEventFlagItemRemoved) {
+ watch->watch_cb(ev->watch_id, DMON_ACTION_DELETE, watch->rootdir, ev->filepath, NULL,
+ watch->user_data);
+ }
+ }
+
+ stb_sb_reset(_dmon.events);
+}
+
+static void* dmon__thread(void* arg)
+{
+ _DMON_UNUSED(arg);
+
+ struct timespec req = { (time_t)10 / 1000, (long)(10 * 1000000) };
+ struct timespec rem = { 0, 0 };
+
+ _dmon.cf_loop_ref = CFRunLoopGetCurrent();
+ dispatch_semaphore_signal(_dmon.thread_sem);
+
+ while (!_dmon.quit) {
+ if (_dmon.modify_watches || pthread_mutex_trylock(&_dmon.mutex) != 0) {
+ nanosleep(&req, &rem);
+ continue;
+ }
+
+ if (_dmon.num_watches == 0) {
+ nanosleep(&req, &rem);
+ pthread_mutex_unlock(&_dmon.mutex);
+ continue;
+ }
+
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__watch_state* watch = &_dmon.watches[i];
+ if (!watch->init) {
+ DMON_ASSERT(watch->fsev_stream_ref);
+ FSEventStreamScheduleWithRunLoop(watch->fsev_stream_ref, _dmon.cf_loop_ref,
+ kCFRunLoopDefaultMode);
+ FSEventStreamStart(watch->fsev_stream_ref);
+
+ watch->init = true;
+ }
+ }
+
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, kCFRunLoopRunTimedOut);
+ dmon__fsevent_process_events();
+
+ pthread_mutex_unlock(&_dmon.mutex);
+ }
+
+ CFRunLoopStop(_dmon.cf_loop_ref);
+ _dmon.cf_loop_ref = NULL;
+ return 0x0;
+}
+
+_DMON_PRIVATE void dmon__unwatch(dmon__watch_state* watch)
+{
+ if (watch->fsev_stream_ref) {
+ FSEventStreamStop(watch->fsev_stream_ref);
+ FSEventStreamInvalidate(watch->fsev_stream_ref);
+ FSEventStreamRelease(watch->fsev_stream_ref);
+ watch->fsev_stream_ref = NULL;
+ }
+
+ memset(watch, 0x0, sizeof(dmon__watch_state));
+}
+
+DMON_API_IMPL void dmon_init(void)
+{
+ DMON_ASSERT(!_dmon_init);
+ pthread_mutex_init(&_dmon.mutex, NULL);
+
+ CFAllocatorContext cf_alloc_ctx = { 0 };
+ cf_alloc_ctx.allocate = dmon__cf_malloc;
+ cf_alloc_ctx.deallocate = dmon__cf_free;
+ cf_alloc_ctx.reallocate = dmon__cf_realloc;
+ _dmon.cf_alloc_ref = CFAllocatorCreate(NULL, &cf_alloc_ctx);
+
+ _dmon.thread_sem = dispatch_semaphore_create(0);
+ DMON_ASSERT(_dmon.thread_sem);
+
+ int r = pthread_create(&_dmon.thread_handle, NULL, dmon__thread, NULL);
+ _DMON_UNUSED(r);
+ DMON_ASSERT(r == 0 && "pthread_create failed");
+
+ // wait for thread to initialize loop object
+ dispatch_semaphore_wait(_dmon.thread_sem, DISPATCH_TIME_FOREVER);
+
+ _dmon_init = true;
+}
+
+DMON_API_IMPL void dmon_deinit(void)
+{
+ DMON_ASSERT(_dmon_init);
+ _dmon.quit = true;
+ pthread_join(_dmon.thread_handle, NULL);
+
+ dispatch_release(_dmon.thread_sem);
+
+ for (int i = 0; i < _dmon.num_watches; i++) {
+ dmon__unwatch(&_dmon.watches[i]);
+ }
+
+ pthread_mutex_destroy(&_dmon.mutex);
+ stb_sb_free(_dmon.events);
+ if (_dmon.cf_alloc_ref) {
+ CFRelease(_dmon.cf_alloc_ref);
+ }
+
+ _dmon_init = false;
+}
+
+_DMON_PRIVATE void dmon__fsevent_callback(ConstFSEventStreamRef stream_ref, void* user_data,
+ size_t num_events, void* event_paths,
+ const FSEventStreamEventFlags event_flags[],
+ const FSEventStreamEventId event_ids[])
+{
+ _DMON_UNUSED(stream_ref);
+
+ union dmon__cast_userdata _userdata;
+ _userdata.ptr = user_data;
+ dmon_watch_id watch_id = dmon__make_id(_userdata.id);
+ DMON_ASSERT(watch_id.id > 0);
+ dmon__watch_state* watch = &_dmon.watches[watch_id.id - 1];
+ char abs_filepath[DMON_MAX_PATH];
+
+ for (size_t i = 0; i < num_events; i++) {
+ const char* filepath = ((const char**)event_paths)[i];
+ long flags = (long)event_flags[i];
+ uint64_t event_id = (uint64_t)event_ids[i];
+ dmon__fsevent_event ev;
+ memset(&ev, 0x0, sizeof(ev));
+
+ dmon__strcpy(abs_filepath, sizeof(abs_filepath), filepath);
+
+ // normalize path (TODO: have to recheck this to be consistent with other platforms)
+ dmon__tolower(abs_filepath, sizeof(abs_filepath),
+ dmon__unixpath(abs_filepath, sizeof(abs_filepath), abs_filepath));
+
+ // strip the root dir
+ DMON_ASSERT(strstr(abs_filepath, watch->rootdir) == abs_filepath);
+ dmon__strcpy(ev.filepath, sizeof(ev.filepath), abs_filepath + strlen(watch->rootdir));
+
+ ev.event_flags = flags;
+ ev.event_id = event_id;
+ ev.watch_id = watch_id;
+ stb_sb_push(_dmon.events, ev);
+ }
+}
+
+DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir,
+ void (*watch_cb)(dmon_watch_id watch_id, dmon_action action,
+ const char* dirname, const char* filename,
+ const char* oldname, void* user),
+ uint32_t flags, void* user_data)
+{
+ DMON_ASSERT(watch_cb);
+ DMON_ASSERT(rootdir && rootdir[0]);
+
+ __sync_lock_test_and_set(&_dmon.modify_watches, 1);
+ pthread_mutex_lock(&_dmon.mutex);
+
+ DMON_ASSERT(_dmon.num_watches < DMON_MAX_WATCHES);
+
+ uint32_t id = ++_dmon.num_watches;
+ dmon__watch_state* watch = &_dmon.watches[id - 1];
+ watch->id = dmon__make_id(id);
+ watch->watch_flags = flags;
+ watch->watch_cb = watch_cb;
+ watch->user_data = user_data;
+
+ struct stat root_st;
+ if (stat(rootdir, &root_st) != 0 || !S_ISDIR(root_st.st_mode) ||
+ (root_st.st_mode & S_IRUSR) != S_IRUSR) {
+ _DMON_LOG_ERRORF("Could not open/read directory: %s", rootdir);
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+
+ if (S_ISLNK(root_st.st_mode)) {
+ if (flags & DMON_WATCHFLAGS_FOLLOW_SYMLINKS) {
+ char linkpath[PATH_MAX];
+ char* r = realpath(rootdir, linkpath);
+ _DMON_UNUSED(r);
+ DMON_ASSERT(r);
+
+ dmon__strcpy(watch->rootdir, sizeof(watch->rootdir) - 1, linkpath);
+ } else {
+ _DMON_LOG_ERRORF("symlinks are unsupported: %s. use DMON_WATCHFLAGS_FOLLOW_SYMLINKS",
+ rootdir);
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(0);
+ }
+ } else {
+ dmon__strcpy(watch->rootdir, sizeof(watch->rootdir) - 1, rootdir);
+ }
+
+ // add trailing slash
+ int rootdir_len = strlen(watch->rootdir);
+ if (watch->rootdir[rootdir_len - 1] != '/') {
+ watch->rootdir[rootdir_len] = '/';
+ watch->rootdir[rootdir_len + 1] = '\0';
+ }
+
+ // create FS objects
+ CFStringRef cf_dir = CFStringCreateWithCString(NULL, watch->rootdir, kCFStringEncodingUTF8);
+ CFArrayRef cf_dirarr = CFArrayCreate(NULL, (const void**)&cf_dir, 1, NULL);
+
+ FSEventStreamContext ctx;
+ union dmon__cast_userdata userdata;
+ userdata.id = id;
+ ctx.version = 0;
+ ctx.info = userdata.ptr;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+ watch->fsev_stream_ref = FSEventStreamCreate(_dmon.cf_alloc_ref, dmon__fsevent_callback, &ctx,
+ cf_dirarr, kFSEventStreamEventIdSinceNow, 0.25,
+ kFSEventStreamCreateFlagFileEvents);
+
+
+ CFRelease(cf_dirarr);
+ CFRelease(cf_dir);
+
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+ return dmon__make_id(id);
+}
+
+DMON_API_IMPL void dmon_unwatch(dmon_watch_id id)
+{
+ DMON_ASSERT(id.id > 0);
+
+ __sync_lock_test_and_set(&_dmon.modify_watches, 1);
+ pthread_mutex_lock(&_dmon.mutex);
+
+ int index = id.id - 1;
+ DMON_ASSERT(index < _dmon.num_watches);
+
+ dmon__unwatch(&_dmon.watches[index]);
+ if (index != _dmon.num_watches - 1) {
+ dmon__swap(_dmon.watches[index], _dmon.watches[_dmon.num_watches - 1], dmon__watch_state);
+ }
+ --_dmon.num_watches;
+
+ pthread_mutex_unlock(&_dmon.mutex);
+ __sync_lock_test_and_set(&_dmon.modify_watches, 0);
+}
+
+// clang-format off
+#endif
+
+#endif // DMON_IMPL
+#endif // __DMON_H__
+// clang-format on
diff --git a/framework/3rd/dmon/test.c b/framework/3rd/dmon/test.c
new file mode 100755
index 0000000..dabc631
--- /dev/null
+++ b/framework/3rd/dmon/test.c
@@ -0,0 +1,40 @@
+#include
+
+#define DMON_IMPL
+#include "dmon.h"
+
+static void watch_callback(dmon_watch_id watch_id, dmon_action action, const char* rootdir,
+ const char* filepath, const char* oldfilepath, void* user)
+{
+ (void)(user);
+ (void)(watch_id);
+
+ switch (action) {
+ case DMON_ACTION_CREATE:
+ printf("CREATE: [%s]%s\n", rootdir, filepath);
+ break;
+ case DMON_ACTION_DELETE:
+ printf("DELETE: [%s]%s\n", rootdir, filepath);
+ break;
+ case DMON_ACTION_MODIFY:
+ printf("MODIFY: [%s]%s\n", rootdir, filepath);
+ break;
+ case DMON_ACTION_MOVE:
+ printf("MOVE: [%s]%s -> [%s]%s\n", rootdir, oldfilepath, rootdir, filepath);
+ break;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc > 1) {
+ dmon_init();
+ puts("waiting for changes ..");
+ dmon_watch(argv[1], watch_callback, DMON_WATCHFLAGS_RECURSIVE, NULL);
+ getchar();
+ dmon_deinit();
+ } else {
+ puts("usage: test dirname");
+ }
+ return 0;
+}
diff --git a/framework/3rd/ffi-lua b/framework/3rd/ffi-lua
new file mode 160000
index 0000000..70a0611
--- /dev/null
+++ b/framework/3rd/ffi-lua
@@ -0,0 +1 @@
+Subproject commit 70a061109d8f9ba36442c27fafc2f6e6c8c7af99
diff --git a/framework/3rd/glm b/framework/3rd/glm
new file mode 160000
index 0000000..84f2045
--- /dev/null
+++ b/framework/3rd/glm
@@ -0,0 +1 @@
+Subproject commit 84f2045a79a4aa2454801a98e2de0401bd9c8aee
diff --git a/framework/3rd/moon b/framework/3rd/moon
new file mode 160000
index 0000000..7f1f94b
--- /dev/null
+++ b/framework/3rd/moon
@@ -0,0 +1 @@
+Subproject commit 7f1f94b66762df19570505219c9031f9a411c649
diff --git a/framework/3rd/moon/.gitignore b/framework/3rd/moon/.gitignore
deleted file mode 100644
index 6e519c8..0000000
--- a/framework/3rd/moon/.gitignore
+++ /dev/null
@@ -1,30 +0,0 @@
-# docco output directory
-#docs/
-
-# local files for remembering stuff
-HISTO
-TODO
-
-# temporary files
-.*.swp
-
-# object files
-*.o
-*.obj
-
-# libraries
-*.so
-*.dll
-*.a
-*.lib
-*.exp
-
-# executables
-*.exe
-
-# precompiled Lua bytecode files
-*.luac
-
-# LuaRocks packages
-*.rock
-
diff --git a/framework/3rd/moon/README.md b/framework/3rd/moon/README.md
deleted file mode 100644
index 5847c97..0000000
--- a/framework/3rd/moon/README.md
+++ /dev/null
@@ -1,552 +0,0 @@
-# Moon -- A C Binding Toolkit for Lua #
-
-This library provides new convenience functions for binding C types to
-Lua as userdata for Lua 5.1, Lua 5.2, and Lua 5.3. It supports objects
-with different lifetimes, polymorphic type checking, type-safe binding
-of tagged unions or embedded structs, properties and methods at the
-same time, and uniform handling of pointers to objects using a simple
-and small set of API functions.
-
-
-## Using this Library ##
-
-This package includes a header file `moon.h` and the corresponding
-source file `moon.c`. To use this package you need to include the
-header file wherever you want to call one of the macros/functions
-defined within. If you just have a single source file where you want
-to use those functions, you are done: `moon.h` includes `moon.c` and
-makes every function `static`. If you have multiple source files that
-need functions/macros from this library, this approach is flawed,
-because you will end up with multiple versions of the same functions.
-Instead include the header wherever you need it, but when you compile
-those source files, define the macro `MOON_PREFIX` to a unique name
-to use for all functions in the `moon` library. You also have to
-compile and link `moon.c` using the same define. This approach will
-change the common `moon_` prefix to your custom prefix behind the
-scenes to avoid linker errors in case another library also links to
-`moon.c`.
-The header file `moon_flag.h` can be included whenever needed, but it
-depends on the functions defined in `moon.c`. The `moon_dlfix.h`
-header is completely independent, but relies on some platform specific
-functions.
-
-
-## Reference ##
-
-This section lists all provided macros/functions.
-
-
-### `moon.h`/`moon.c` ###
-
-The main part of the moon toolkit.
-
-
-#### `MOON_EXPORT`, `MOON_IMPORT`, `MOON_LOCAL` ####
-
- #define MOON_EXPORT
- #define MOON_IMPORT
- #define MOON_LOCAL
-
-Macros for specifying symbol visibility.
-
-
-#### `MOON_CONCAT` ####
-
- #define MOON_CONCAT( _a, _b )
-
-A macro that evaluates both arguments and joins them together. You can
-use that to build valid C identifiers with custom prefixes or
-suffixes.
-
-
-#### `MOON_STRINGIFY` ####
-
- #define MOON_STRINGIFY( _v )
-
-A macro that has the same effect as `#_v`, but works outside of a
-macro substitution.
-
-
-#### `moon_object_header` ####
-
- typedef struct {
- unsigned char flags;
- unsigned char cleanup_offset;
- unsigned char vcheck_offset;
- unsigned char object_offset;
- } moon_object_header;
-
-Common data structure shared by all userdata objects created via the
-moon toolkit. The object may have optional fields following the memory
-of this header structure, stored at the given offsets. The `flags`
-field is a bit mask describing the details of the object. A pointer to
-this header can be obtained by using plain `lua_touserdata` on a moon
-object.
-
-
-#### `moon_object_cast` ####
-
- typedef void* (*moon_object_cast)( void* );
-
-Function pointer type for conversion functions used by `moon_defcast`.
-
-
-#### `moon_object_destructor` ####
-
- typedef void (*moon_object_destructor)( void* );
-
-Function pointer type for cleanup functions of moon objects.
-
-
-#### `MOON_OBJECT_IS_VALID`, `MOON_OBJECT_IS_POINTER` ####
-
- #define MOON_OBJECT_IS_VALID 0x01
- #define MOON_OBJECT_IS_POINTER 0x02
-
-Values stored in the `flags` field of the `moon_object_header`
-structure. The only value interesting for users of the library is the
-`MOON_OBJECT_IS_VALID` flag which is reset automatically by the
-`moon_killobject` function to signal that the destructor has already
-run.
-
-
-#### `moon_defobject` ####
-
- /* [ -nup, +0, e ] */
- void moon_defobject( lua_State* L,
- char const* metatable_name,
- size_t userdata_size,
- luaL_Reg const* methods,
- int nup );
-
-This function creates a new metatable and registers the functions in
-the `luaL_Reg` array (functions starting with double underscores `__`
-go into the metatable, functions starting with a fullstop `.` are
-setup as properties, and the rest goes into a table used by the
-`__index` metafield). Property functions act as `__index` and
-`__newindex` functions at the same time, i.e. they should return a
-value when called with two arguments, and assign the third value when
-called with three. If the `luaL_Reg` array also contains an `__index`
-and/or `__newindex` function, those functions are called as fallbacks
-when method/property lookup has failed. In case a metatable with the
-given name already exists, an error is raised. The `userdata_size` is
-stored in the metatable for the `moon_newobject` function -- use a
-size of 0 to prohibit use of `moon_newobject` (e.g. for incomplete
-types). If `nup` is non-zero, it pops those upvalues from the current
-Lua stack top and makes them available to all registered functions
-(metamethods, property functions, *and* methods). A `__gc` metamethod
-and a default `__tostring` metamethod are provided by `moon_defobject`
-as well.
-
-
-#### `moon_newobject` ####
-
- /* [ -0, +1, e ] */
- void* moon_newobject( lua_State* L,
- char const* metatable_name,
- moon_object_destructor destructor );
-
-This function allocates a userdata, sets a metatable, and stores the
-cleanup function for later use by the `__gc` metamethod or the
-`moon_killobject` function. It throws an error if the `metatable_name`
-has not been registered via the `moon_defobject` function. The new
-userdata object is pushed to the top of the Lua stack, and a pointer
-to the payload (*not* the `moon_object_header` structure) is returned.
-
-
-#### `moon_newpointer` ####
-
- /* [ -0, +1, e ] */
- void** moon_newpointer( lua_State* L,
- char const* metatable_name,
- moon_object_destructor destructor );
-
-This function allocates a userdata suitable for storing a pointer,
-sets a metatable, and stores the cleanup function for later use by the
-`__gc` metamethod or the `moon_killobject` function. It is equivalent
-to `moon_newobject` with the difference that the payload is stored as
-a pointer, not inside the userdata memory. The pointer is initialized
-to `NULL` when this function returns, and may be set by assigning to
-the memory location pointed to by the return value.
-
-
-#### `moon_newfield` ####
-
- /* [ -0, +1, e ] */
- void** moon_newfield( lua_State* L,
- char const* metatable_name,
- int idx,
- int (*isvalid)( void* p ),
- void* p );
-
-This function allocates a userdata suitable for storing a pointer, and
-sets a metatable. It is similar to `moon_newpointer`, but it is
-intended for exposing a data structure embedded within another
-userdata (referenced by stack position `idx`). The resulting moon
-object keeps the parent userdata alive by storing a reference in its
-uservalue table. If `idx` is `0`, no uservalue table is set. Setting a
-cleanup function is not possible, because the parent userdata is
-responsible for cleaning up memory and other resources.
-If an `isvalid` function pointer is provided, it is called by the
-`moon_checkobject`/`moon_testobject` functions to check whether the
-object is still valid. This can be used to make sure that a tagged
-union used as parent userdata still has the correct type, or that the
-parent userdata hasn't released any necessary resources prior to
-garbage collection. If the value referenced by `idx` is a moon object
-that also has an `isvalid` check registered, all checks are performed
-in the order from parent object(s) to child object.
-
-
-#### `moon_getmethods` ####
-
- /* [ -0, +(0|1), e ] */
- int moon_getmethods( lua_State* L,
- char const* tname );
-
-If the metatable identified by `tname` has methods registered, pushes
-the methods table and returns `LUA_TTABLE`. Otherwise nothing is
-pushed and `LUA_TNIL` is returned. This function only works for moon
-objects and raises an error if the metatable `tname` wasn't registered
-via `moon_defobject`.
-
-
-#### `moon_killobject` ####
-
- /* [ -0, +0, e ] */
- void moon_killobject( lua_State* L,
- int idx );
-
-If the moon object at the given stack index is valid, its cleanup
-function is run, and the object is marked as invalid (to prevent the
-cleanup function from running again). This function can be used to
-reclaim resources before the object becomes unreachable.
-
-
-#### `moon_defcast` ####
-
- /* [ -0, +0, e ] */
- void moon_defcast( lua_State* L,
- char const* tname1,
- char const* tname2,
- moon_object_cast cast );
-
-Registers the conversion function `cast` for converting userdata
-objects of type `tname1` to type `tname2`. The `cast` function is
-called automatically by `moon_checkobject( L, idx, tname2 )` when
-applied to an object of type `tname1`, so function implementations can
-be reused without extra work. The metatable `tname1` must already
-exist and belong to a moon object type (created via `moon_defobject`).
-
-
-#### `moon_checkobject` ####
-
- /* [ -0, +0, v ] */
- void* moon_checkobject( lua_State* L,
- int idx,
- char const* metatable_name );
-
-This function ensures that the value stored at stack index `idx`
-
-1. is a full userdata
-2. is a moon object
-3. has the metatable identified by `metatable_name` or has a
- cast function to `metatable_name` registered
-4. has the `MOON_OBJECT_IS_VALID` flag set
-5. all `isvalid` functions return a non-zero value (for objects
- created via `moon_newfield`)
-6. contains a non-`NULL` pointer value (for objects created via
- `moon_newpointer` or `moon_newfield`).
-
-If any of those conditions are false, an error is raised. Otherwise
-this function returns a pointer to the object's memory (meaning the
-objects created via `moon_newpointer` and `moon_newfield` are
-dereferenced once, and if necessary the registered cast function is
-called).
-
-
-#### `moon_testobject` ####
-
- /* [ -0, +0, e ] */
- void* moon_testobject( lua_State* L,
- int idx,
- char const* metatable_name );
-
-Performs the same checks as `moon_checkobject`, but returns `NULL` if
-any of those conditions are false instead of raising an error.
-
-
-#### `moon_checkint` ####
-
- /* [ -0, +0, v ] */
- lua_Integer moon_checkint( lua_State* L,
- int idx,
- lua_Integer min,
- lua_Integer max );
-
-This function works like `luaL_checkinteger` but additionally ensures
-that the given value is in the range [`min`, `max`], or else an error
-is thrown.
-
-
-#### `moon_optint` ####
-
- /* [ -0, +0, v ] */
- lua_Integer moon_optint( lua_State* L,
- int idx,
- lua_Integer min,
- lua_Integer max,
- lua_Integer def );
-
-Similar to `moon_checkint` but uses the default value `def` if the
-value at the given stack position is `nil` or `none`.
-
-
-#### `moon_atexit` ####
-
- /* [ -0, +1, e ] */
- int* moon_atexit( lua_State* L,
- lua_CFunction cleanup );
-
-This function puts an integer-sized userdata (initialized to 0) in the
-registry and sets the given `cleanup` function as `__gc` metamethod.
-The userdata is also pushed to the top of the Lua stack, and returned
-as an `int` pointer.
-Use this function if you want to call a cleanup function when the Lua
-state is closed, but only if some initialization succeeded. The usual
-approach is as follows:
-
-1. Call `moon_atexit` registering your cleanup function.
-2. Do your initialization.
-3. If successful, you set the `int` pointer to non-zero, which is
- almost atomic and can't fail, and pop the userdata.
-4. When the cleanup function is called, check for a non-zero value
- before actually cleaning up.
-
-
-#### `moon_setuvfield` ####
-
- /* [ -1, +0, e ] */
- void moon_setuvfield( lua_State* L,
- int idx,
- char const* key );
-
-This function pops the value at the top of the stack and stores it
-under `key` in the environment/uservalue table of the object at stack
-position `idx`.
-
-
-#### `moon_getuvfield` ####
-
- /* [ -0, +(0|1), e ] */
- int moon_getuvfield( lua_State* L,
- int idx,
- char const* key );
-
-This function works similar to `luaL_getmetafield`, but it looks for
-`key` in the environment/uservalue table of the object at index `idx`,
-and pushes the corresponding value to the top of the stack. If there
-is no uservalue table or no such field, nothing is pushed and
-`LUA_TNIL` is returned. Otherwise, the return value is the type of the
-pushed value.
-
-
-#### `moon_getcache` ####
-
- /* [ -0, +1, e ] */
- void moon_getcache( lua_State* L,
- int idx );
-
-This function looks up and pushes a weak-valued table under a private
-key in the table given by index `idx` (often `LUA_REGISTRYINDEX`). If
-the weak-valued table doesn't exist yet, it is created automatically.
-This function is useful to map lightuserdata to full userdata, but it
-can also be used to cache full userdata for enum values (using
-separate caches per enum type), etc.
-
-
-#### `moon_stack_assert` ####
-
- /* [ -0, +0, v ] */
- void moon_stack_assert( lua_State* L,
- ... );
-
-This "function" is implemented as a macro that evaluates to `void` if
-`NDEBUG` is defined. If it is not, it tries to match the type
-specifications (strings) given as arguments to the values at the top
-of the Lua stack. Every mismatch is reported on `stderr`, and finally
-the whole Lua stack is dumped to `stderr` using the `moon_stack`
-function below, and an error is raised. Currently the following type
-specifications are supported:
-
-* `"n"`: nil
-* `"b"`: boolean
-* `"l"`: lightuserdata
-* `"i"`: integer (equivalent to `"d"` before Lua 5.3)
-* `"d"`: number (think `double`)
-* `"s"`: string
-* `"t"`: table
-* `"f"`: function
-* `"u"`: userdata
-* `"c"`: coroutine
-* `"a"`: any (non-nil) value
-
-You can combine the single letter options to express alternatives, so
-e.g. `"tf"` means: table or function.
-
-
-#### `moon_stack` ####
-
- /* [ -0, +0, - ] */
- void moon_stack( lua_State* L );
-
-This "function" is also implemented as a macro that evaluates to
-`void` in case `NDEBUG` is defined. Otherwise it prints the current
-contents of the Lua stack in human-readable format to `stderr`.
-
-
-#### `moon_absindex` ####
-
-Compatiblity macro for `lua_absindex`, but also available on Lua 5.1
-as a function.
-
-
-#### `moon_derive` ####
-
- int moon_derive( lua_State* L );
-
-A `lua_CFunction` that may be registered as part of your module and
-allows Lua code to subclass a moon object. When called it expects two
-strings as arguments: a new (non-existing) type name and an old
-(existing) type name of a moon object type. It sets up the new type
-name as an alias to the old type but with a different methods table.
-The new methods table (initially a copy of the methods of the old
-type) is returned.
-
-
-#### `moon_downcast` ####
-
- int moon_downcast( lua_State* L );
-
-A `lua_CFunction` that may be registered as part of your module and
-allows Lua code to change the type of a moon object to a type created
-via `moon_derive`. It is typically used in constructors of derived
-types, and expects a moon object and the new type name as arguments.
-If successful, the object (with its metatable replaced) is returned.
-
-
-### `moon_flag.h` ###
-
-`moon_flag.h` is a macro file, that can be included multiple times and
-each time defines a new userdata type as a type-safe representation of
-a given enum/flag type in Lua. The resulting userdata values support
-`+` (bitwise or, in Lua 5.3 also `|`), `-` (create a new value with
-certain bits cleared), and calling (test if all bits are set). For Lua
-5.3 also bitwise "and" and bitwise "not" are defined.
-Parameters are passed as macros before including the macro file. Any
-arguments and all internal macros are `#undef`ed before leaving the
-macro file. The following parameters are recognized:
-
-* `MOON_FLAG_NAME` (required): A metatable name used for defining a
- userdata type.
-* `MOON_FLAG_TYPE` (required): The underlying enum/flag type that is
- handled by the custom userdata.
-* `MOON_FLAG_SUFFIX` (required): All defined functions have this
- suffix (and the `moon_flag_` prefix) to make them unique.
-* `MOON_FLAG_NOBITOPS` (optional): If this macro is defined, no
- metamethods for bitwise operations are created. This includes
- `__add`, `__sub`, and `__call` metamethods. If you do this, you
- should think about using strings and `luaL_checkoption` instead of
- userdata for representing your flags in Lua.
-* `MOON_FLAG_NORELOPS` (optional): If this macro is defined, the
- `__eq` metamethod is not created.
-* `MOON_FLAG_USECACHE` (optional): The constructor function for this
- flag looks in a local cache before creating a new full userdata,
- and returns the cached value if possible. This way each enum/flag
- value has at most one userdata associated with it.
-* `MOON_FLAG_EQMETHOD( _a, _b )` (optional): If you need a custom
- comparison operation instead of the usual `==`, define this macro.
-
-The following (static) functions will be defined, unless they are
-disabled via one of the parameter macros above:
-
- /* [ -0, +0, e ] */
- void moon_flag_def_SUFFIX( lua_State* L );
- /* [ -0, +1, e ] */
- void moon_flag_new_SUFFIX( lua_State* L, TYPE value );
- /* [ -0, +0, v ] */
- TYPE moon_flag_get_SUFFIX( lua_State* L, int idx );
-
- int moon_flag_add_SUFFIX( lua_State* L );
- int moon_flag_sub_SUFFIX( lua_State* L );
- int moon_flag_call_SUFFIX( lua_State* L );
- int moon_flag_and_SUFFIX( lua_State* L ); /* Lua 5.3+ */
- int moon_flag_not_SUFFIX( lua_State* L ); /* Lua 5.3+ */
- int moon_flag_eq_SUFFIX( lua_State* L );
-
-The last six are metamethods and not supposed to be called from C.
-`moon_flag_def_SUFFIX` defines the new type, creates the metatable and
-registers all metamethods. `moon_flag_new_SUFFIX` pushes a userdata
-representing the given value to the top of the Lua stack, while
-`moon_flag_get_SUFFIX` returns the corresponding enum value from a
-userdata on the Lua stack (or raises an error).
-
-
-### `moon_dlfix.h` ###
-
-On Linux and BSDs (and possibly other Unix machines) binary extension
-modules aren't linked to the Lua library directly, but instead expect
-the main executable to reexport the Lua API. If you don't have control
-over the main executable (e.g. you are writing a plugin for a 3rd
-party program), you are out of luck. This header file tries to
-reexport the Lua API from the shared library linked to your plugin to
-make it available for extension modules. It relies on some platform
-specific tricks, so it probably won't work everywhere.
-
-
-#### `MOON_DLFIX` ####
-
- #define MOON_DLFIX()
-
-This macro uses the dynamic linker to search for the Lua API in an
-already loaded shared library and reexport it for extension modules.
-If the necessary linker tricks don't work on the given platform, this
-macro evaluates to a `void` expression, and you will continue to get
-the usual unresolved symbol errors when loading a binary extension
-module.
-
-
-#### `MOON_DLFIX_LIBNAME` ####
-
-If the builtin heuristics fail to find the shared Lua library you can
-specify the library name/path by defining this macro.
-
-
-#### `MOON_DLFIX_LIBPREFIX` ####
-
-For some OSes *all* loaded shared libraries is searched for an ELF
-object that contains the Lua symbols. Since this procedure also finds
-shared objects that have the Lua library as a dependency, the library
-name is checked for a known prefix to make sure that only the actual
-Lua library is exported. The default is `"liblua"`, but you can change
-it by defining this macro.
-
-
-## Contact ##
-
-Philipp Janda, siffiejoe(a)gmx.net
-
-Comments and feedback are always welcome.
-
-
-## License ##
-
-`moon` is *copyrighted free software* distributed under the Tiny
-license. The full license text follows:
-
- moon (c) 2013-2016 Philipp Janda
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-
-
diff --git a/framework/3rd/moon/examples/dlfixex.c b/framework/3rd/moon/examples/dlfixex.c
deleted file mode 100644
index e8d620f..0000000
--- a/framework/3rd/moon/examples/dlfixex.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include
-#include
-#include
-#include "plugin.h"
-
-int main( void ) {
- int ret = EXIT_FAILURE;
- void* lib = dlopen( "./plugin.so", RTLD_LAZY|RTLD_LOCAL );
- void* sym = NULL;
- plugin f;
- if( !lib || !(sym = dlsym( lib, PLUGIN )) ) {
- fprintf( stderr, "ERROR: %s\n", dlerror() );
- goto error;
- }
- f = (plugin)sym;
- ret = f();
-error:
- if( lib )
- dlclose( lib );
- return ret;
-}
-
diff --git a/framework/3rd/moon/examples/flgex.c b/framework/3rd/moon/examples/flgex.c
deleted file mode 100644
index 04cc310..0000000
--- a/framework/3rd/moon/examples/flgex.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include
-#include
-#include "moon.h"
-
-
-#define MOON_FLAG_NAME "X"
-#define MOON_FLAG_TYPE unsigned
-#define MOON_FLAG_SUFFIX X
-#define MOON_FLAG_USECACHE
-#include "moon_flag.h"
-
-#define MOON_FLAG_NAME "Y"
-#define MOON_FLAG_TYPE unsigned
-#define MOON_FLAG_SUFFIX Y
-#include "moon_flag.h"
-
-
-static int flgex_getXmethods( lua_State* L ) {
- if( moon_getmethods( L, "X" ) == LUA_TNIL )
- lua_pushnil( L );
- return 1;
-}
-
-
-int luaopen_flgex( lua_State* L ) {
- luaL_Reg const flgex_funcs[] = {
- { "getXmethods", flgex_getXmethods },
- { NULL, NULL }
- };
- /* define the flags and create their metatables */
- moon_flag_def_X( L );
- moon_flag_def_Y( L );
-#if LUA_VERSION_NUM < 502
- luaL_register( L, "flgex", flgex_funcs );
-#else
- luaL_newlib( L, flgex_funcs );
-#endif
- /* create some predefined flags */
- moon_flag_new_X( L, 0 );
- lua_setfield( L, -2, "NULL" );
- moon_flag_new_X( L, 1 );
- lua_setfield( L, -2, "ONE" );
- moon_flag_new_X( L, 2 );
- lua_setfield( L, -2, "TWO" );
- moon_flag_new_Y( L, 4 );
- lua_setfield( L, -2, "THREE" );
- moon_flag_new_Y( L, 8 );
- lua_setfield( L, -2, "FOUR" );
- /* we don't use those functions in this example: */
- (void)moon_flag_get_X;
- (void)moon_flag_get_Y;
- return 1;
-}
-
diff --git a/framework/3rd/moon/examples/objex.c b/framework/3rd/moon/examples/objex.c
deleted file mode 100644
index 0c2188c..0000000
--- a/framework/3rd/moon/examples/objex.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Example code for userdata handling in the moon toolkit.
- *
- * The moon toolkits provides the following functions for handling
- * userdata in an easy and safe way:
- * - moon_defobject
- * - moon_newobject
- * - moon_newpointer
- * - moon_newfield
- * - moon_killobject
- * - moon_checkobject
- * - moon_testobject
- * - moon_defcast
- *
- * Using those functions enables you to
- * - Create and register a new metatable for a C type in a single
- * function call, including methods and metamethods with upvalues.
- * - Have properties and methods for an object at the same time.
- * - Use C values and pointers to those values in a uniform way.
- * - Support multiple different ways to create/destroy a C type.
- * - Expose fields embedded in another object in a type-safe way.
- * - Bind tagged unions in a type-safe way.
- * - Define functions that release resources in a safe way before
- * the object becomes unreachable.
- * - Use userdata polymorphically (use one method implementation for
- * multiple similar types).
- */
-#include
-#include
-#include
-#include
-#include
-#include
-#include "moon.h"
-
-
-/* Types to be exposed to Lua: */
-typedef struct {
- int x;
- int y;
-} D;
-
-typedef struct {
- D d;
-} C;
-
-typedef struct {
- double f;
-} B;
-
-#define TYPE_B 1
-#define TYPE_C 2
-
-typedef struct {
- int tag;
- union {
- B b;
- C c;
- } u;
-} A;
-
-
-/* Check functions to make sure that embedded userdata are still
- * valid. A change in the tagged union (A_switch) or running a cleanup
- * function (C_close) can make embedded userdata invalid. */
-static int type_b_check( void* p ) {
- int* tagp = p;
- int res = *tagp == TYPE_B;
- return res;
-}
-
-static int type_c_check( void* p ) {
- int* tagp = p;
- int res = *tagp == TYPE_C;
- return res;
-}
-
-static int object_valid_check( void* p ) {
- unsigned char* flagp = p;
- int res = *flagp & MOON_OBJECT_IS_VALID;
- return res;
-}
-
-
-/* Types that are similar can share one method implementation, but a
- * pointer to one type has to be transformed to a pointer to the other
- * type. This is probably much more useful when binding C++ libraries
- * with proper type hierarchies! */
-static void* C_to_D( void* p ) {
- C* c = p;
- printf( "casting C to D\n" );
- return &(c->d);
-}
-
-
-
-/* The (meta-)methods are pretty straightforward. Just use
- * `moon_checkobject` instead of `luaL_checkudata`. */
-static int A_index( lua_State* L ) {
- A* a = moon_checkobject( L, 1, "A" );
- char const* key = luaL_checkstring( L, 2 );
- if( 0 == strcmp( key, "tag" ) ) {
- lua_pushstring( L, a->tag == TYPE_B ? "b" : "c" );
- } else if( 0 == strcmp( key, "b" ) && a->tag == TYPE_B ) {
- /* To avoid creating the sub-userdata on every __index access, the
- * userdata values are cached in the uservalue field of the parent
- * using the same field name as in the struct. */
- if( moon_getuvfield( L, 1, "b" ) == LUA_TNIL ) {
- /* Create a new userdata that represents a field in another
- * object already exposed to Lua. A gc function is unnecessary
- * since the parent userdata already takes care of that.
- * However, the parent userdata must be kept alive long enough
- * (by putting the value at index 1 into the uservalue table of
- * the new userdata), and the new userdata may only be used as
- * long as the `a->tag` field satisfies the `type_b_check`
- * function! */
- void** p = moon_newfield( L, "B", 1, type_b_check, &(a->tag) );
- /* The userdata stores a pointer to the `a->b` field. */
- *p = &(a->u.b);
- lua_pushvalue( L, -1 );
- moon_setuvfield( L, 1, "b" );
- }
- } else if( 0 == strcmp( key, "c" ) && a->tag == TYPE_C ) {
- if( moon_getuvfield( L, 1, "c" ) == LUA_TNIL ) {
- void** p = moon_newfield( L, "C", 1, type_c_check, &(a->tag) );
- *p = &(a->u.c);
- lua_pushvalue( L, -1 );
- moon_setuvfield( L, 1, "c" );
- }
- } else
- lua_pushnil( L );
- return 1;
-}
-
-
-static int A_switch( lua_State* L ) {
- A* a = moon_checkobject( L, 1, "A" );
- lua_settop( L, 1 );
- if( a->tag == TYPE_B ) {
- a->tag = TYPE_C;
- a->u.c.d.x = 0;
- a->u.c.d.y = 0;
- } else {
- a->tag = TYPE_B;
- a->u.b.f = 0.0;
- }
- return 1;
-}
-
-
-static int A_printme( lua_State* L ) {
- A* a = moon_checkobject( L, 1, "A" );
- if( a->tag == TYPE_B )
- printf( "A { u.b.f = %g }\n", a->u.b.f );
- else
- printf( "A { u.c.d = { x = %d, y = %d } }\n",
- a->u.c.d.x, a->u.c.d.y );
- return 0;
-}
-
-
-static int B_property_f( lua_State* L ) {
- B* b = moon_checkobject( L, 1, "B" );
- printf( "property{f} B (uv1: %d, uv2: %d)\n",
- (int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
- (int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
- if( lua_gettop( L ) < 3 ) { /* __index */
- lua_pushnumber( L, b->f );
- return 1;
- } else { /* __newindex */
- b->f = luaL_checknumber( L, 3 );
- return 0;
- }
-}
-
-#if 0
-static int B_index( lua_State* L ) {
- B* b = moon_checkobject( L, 1, "B" );
- char const* key = luaL_checkstring( L, 2 );
- printf( "__index B (uv1: %d, uv2: %d)\n",
- (int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
- (int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
- if( 0 == strcmp( key, "f" ) ) {
- lua_pushnumber( L, b->f );
- } else
- lua_pushnil( L );
- return 1;
-}
-
-
-static int B_newindex( lua_State* L ) {
- B* b = moon_checkobject( L, 1, "B" );
- char const* key = luaL_checkstring( L, 2 );
- printf( "__newindex B (uv1: %d, uv2: %d)\n",
- (int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
- (int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
- if( 0 == strcmp( key, "f" ) )
- b->f = luaL_checknumber( L, 3 );
- return 0;
-}
-#endif
-
-
-static int B_printme( lua_State* L ) {
- B* b = moon_checkobject( L, 1, "B" );
- printf( "B { f = %g }\n", b->f );
- return 0;
-}
-
-
-static int C_index( lua_State* L ) {
- C* c = moon_checkobject( L, 1, "C" );
- /* You can get a pointer to the `moon_object_header` structure
- * common to all objects created via the moon toolkit by using the
- * normal `lua_touserdata` function: */
- moon_object_header* h = lua_touserdata( L, 1 );
- char const* key = luaL_checkstring( L, 2 );
- printf( "__index C (uv1: %d, uv2: %d)\n",
- (int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
- (int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
- if( 0 == strcmp( key, "d" ) ) {
- if( moon_getuvfield( L, 1, "d" ) == LUA_TNIL ) {
- /* The `object_valid_check` makes sure that the parent object
- * has the `MOON_OBJECT_IS_VALID` flag set. This flag is reset
- * by the `moon_killobject` function. */
- void** p = moon_newfield( L, "D", 1, object_valid_check, &h->flags );
- *p = &(c->d);
- lua_pushvalue( L, -1 );
- moon_setuvfield( L, 1, "d" );
- }
- } else
- lua_pushnil( L );
- return 1;
-}
-
-
-static int C_newindex( lua_State* L ) {
- C* c = moon_checkobject( L, 1, "C" );
- char const* key = luaL_checkstring( L, 2 );
- printf( "__newindex C (uv1: %d, uv2: %d)\n",
- (int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
- (int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
- if( 0 == strcmp( key, "d" ) ) {
- D* d = moon_checkobject( L, 3, "D" );
- c->d = *d;
- }
- return 0;
-}
-
-
-static int C_close( lua_State* L ) {
- /* Use `moon_testobject` here to test it. `moon_checkobject` would
- * make more sense in practice! */
- if( !moon_testobject( L, 1, "C" ) )
- luaL_error( L, "need a 'C' object" );
- /* Run cleanup function (if any) to release resources and mark the
- * C object as invalid. `moon_checkobject` will raise an error for
- * invalid objects. */
- moon_killobject( L, 1 );
- return 0;
-}
-
-
-static int C_printme( lua_State* L ) {
- C* c = moon_checkobject( L, 1, "C" );
- printf( "C { d = { x = %d, y = %d } } (uv1: %d, uv2: %d)\n",
- c->d.x, c->d.y,
- (int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
- (int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
- return 0;
-}
-
-
-static int D_index( lua_State* L ) {
- D* d = moon_checkobject( L, 1, "D" );
- char const* key = luaL_checkstring( L, 2 );
- if( 0 == strcmp( key, "x" ) )
- lua_pushinteger( L, d->x );
- else if( 0 == strcmp( key, "y" ) )
- lua_pushinteger( L, d->y );
- else {
-#if LUA_VERSION_NUM < 502
- lua_getfenv( L, 1 );
-#else
- lua_getuservalue( L, 1 );
-#endif
- lua_pushvalue( L, 2 );
- lua_rawget( L, -2 );
- lua_replace( L, -2 );
- }
- return 1;
-}
-
-
-static int D_newindex( lua_State* L ) {
- D* d = moon_checkobject( L, 1, "D" );
- char const* key = luaL_checkstring( L, 2 );
- if( 0 == strcmp( key, "x" ) )
- d->x = (int)moon_checkint( L, 3, INT_MIN, INT_MAX );
- else if( 0 == strcmp( key, "y" ) )
- d->y = (int)moon_checkint( L, 3, INT_MIN, INT_MAX );
- else {
-#if LUA_VERSION_NUM < 502
- lua_getfenv( L, 1 );
-#else
- lua_getuservalue( L, 1 );
-#endif
- lua_pushvalue( L, 2 );
- lua_pushvalue( L, 3 );
- lua_rawset( L, -3 );
- }
- return 0;
-}
-
-
-static int D_printme( lua_State* L ) {
- D* d = moon_checkobject( L, 1, "D" );
- printf( "D { x = %d, y = %d }\n", d->x, d->y );
- return 0;
-}
-
-
-static int D_vcall( lua_State* L ) {
- moon_checkobject( L, 1, "D" );
- lua_getfield( L, 1, "func" );
- if( lua_isfunction( L, -1 ) ) {
- lua_insert( L, 1 );
- lua_call( L, lua_gettop( L )-1, LUA_MULTRET );
- return lua_gettop( L );
- }
- return 0;
-}
-
-
-static int objex_getAmethods( lua_State* L ) {
- if( moon_getmethods( L, "A" ) == LUA_TNIL )
- lua_pushnil( L );
- return 1;
-}
-
-
-static int objex_newA( lua_State* L ) {
- /* Create a new A object. The memory is allocated inside the
- * userdata when using `moon_newobject`. Here no cleanup function
- * is used (0 pointer). */
- A* ud = moon_newobject( L, "A", 0 );
- ud->tag = TYPE_B;
- ud->u.b.f = 0.0;
- /* `moon_newobject`, and `moon_newpointer` don't allocate a
- * uservalue table by default. `moon_newfield` only does if the
- * given index is non-zero. If you need a uservalue table (e.g. to
- * cache embedded userdatas), you have to add one yourself: */
- lua_newtable( L );
-#if LUA_VERSION_NUM < 502
- lua_setfenv( L, -2 );
-#else
- lua_setuservalue( L, -2 );
-#endif
- return 1;
-}
-
-
-static int objex_newB( lua_State* L ) {
- B* b = moon_newobject( L, "B", 0 );
- b->f = 0.0;
- return 1;
-}
-
-
-static void C_destructor( void* p ) {
- printf( "destroying C: %p\n", p );
-}
-
-static int objex_newC( lua_State* L ) {
- /* Create a C object and register a dummy cleanup function (just
- * for tests): */
- C* c = moon_newobject( L, "C", C_destructor );
- c->d.x = 0;
- c->d.y = 0;
- printf( "creating C: %p\n", (void*)c );
- lua_newtable( L );
-#if LUA_VERSION_NUM < 502
- lua_setfenv( L, -2 );
-#else
- lua_setuservalue( L, -2 );
-#endif
- return 1;
-}
-
-
-static int objex_newD( lua_State* L ) {
- D* d = moon_newobject( L, "D", 0 );
- d->x = 0;
- d->y = 0;
- lua_newtable( L );
-#if LUA_VERSION_NUM < 502
- lua_setfenv( L, -2 );
-#else
- lua_setuservalue( L, -2 );
-#endif
- return 1;
-}
-
-
-static int objex_getD( lua_State* L ) {
- static D d = { 1, 2 };
- /* `moon_newpointer` without a cleanup function can be used to
- * expose a global variable to Lua: */
- void** ud = moon_newpointer( L, "D", 0 );
- *ud = &d;
- lua_newtable( L );
-#if LUA_VERSION_NUM < 502
- lua_setfenv( L, -2 );
-#else
- lua_setuservalue( L, -2 );
-#endif
- return 1;
-}
-
-
-static D* newD( int x, int y ) {
- D* d = malloc( sizeof( *d ) );
- if( d ) {
- printf( "allocating D: %p\n", (void*)d );
- d->x = x;
- d->y = y;
- }
- return d;
-}
-
-static void freeD( void* d ) {
- printf( "deallocating D: %p\n", d );
- free( d );
-}
-
-static int objex_makeD( lua_State* L ) {
- int x = (int)moon_checkint( L, 1, INT_MIN, INT_MAX );
- int y = (int)moon_checkint( L, 2, INT_MIN, INT_MAX );
- /* Usually, `moon_newpointer` is used when your API handles memory
- * allocation and deallocation for its types: */
- void** p = moon_newpointer( L, "D", freeD );
- /* The cleanup function will only run if the pointer is set to a
- * non-NULL value. `moon_checkobject` also will raise an error when
- * passed a NULL object! */
- *p = newD( x, y );
- if( !*p )
- luaL_error( L, "memory allocation error" );
- lua_newtable( L );
-#if LUA_VERSION_NUM < 502
- lua_setfenv( L, -2 );
-#else
- lua_setuservalue( L, -2 );
-#endif
- return 1;
-}
-
-
-int luaopen_objex( lua_State* L ) {
- luaL_Reg const objex_funcs[] = {
- { "getAmethods", objex_getAmethods },
- { "newA", objex_newA },
- { "newB", objex_newB },
- { "newC", objex_newC },
- { "newD", objex_newD },
- { "getD", objex_getD },
- { "makeD", objex_makeD },
- { "derive", moon_derive },
- { "downcast", moon_downcast },
- { NULL, NULL }
- };
- /* You put metamethods and normal methods in the same luaL_Reg
- * array. `moon_defobject` puts the functions in the right place
- * automatically. */
- luaL_Reg const A_methods[] = {
- { "__index", A_index },
- { "switch", A_switch },
- { "printme", A_printme },
- { NULL, NULL }
- };
- luaL_Reg const B_methods[] = {
- { ".f", B_property_f },
-#if 0
- { "__index", B_index },
- { "__newindex", B_newindex },
- { "printme", B_printme },
-#endif
- { NULL, NULL }
- };
- luaL_Reg const C_methods[] = {
- { "__index", C_index },
- { "__newindex", C_newindex },
- { "printme", C_printme },
- /* A C object can be cast to a D object (see below), so C objects
- * can use the methods of the D type! */
- { "printmeD", D_printme },
- { "close", C_close },
- { NULL, NULL }
- };
- luaL_Reg const D_methods[] = {
- { "__index", D_index },
- { "__newindex", D_newindex },
- { "printme", D_printme },
- { "vcall", D_vcall },
- { NULL, NULL }
- };
- /* All object types must be defined once (this creates the
- * metatables): */
- moon_defobject( L, "A", sizeof( A ), A_methods, 0 );
- (void)B_printme; /* avoid warning */
- lua_pushinteger( L, 1 );
- lua_pushinteger( L, 2 );
- moon_defobject( L, "B", sizeof( B ), B_methods, 2 );
- lua_pushinteger( L, 1 );
- lua_pushinteger( L, 2 );
- moon_defobject( L, "C", sizeof( C ), C_methods, 2 );
- moon_defobject( L, "D", sizeof( D ), D_methods, 0 );
- /* Add a type cast from a C object to the embedded D object. The
- * cast is executed automatically during moon_checkobject. */
- moon_defcast( L, "C", "D", C_to_D );
-#if LUA_VERSION_NUM < 502
- luaL_register( L, "objex", objex_funcs );
-#else
- luaL_newlib( L, objex_funcs );
-#endif
- return 1;
-}
-
-
diff --git a/framework/3rd/moon/examples/plugin.c b/framework/3rd/moon/examples/plugin.c
deleted file mode 100644
index 0113f1b..0000000
--- a/framework/3rd/moon/examples/plugin.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include "plugin.h"
-#include "moon_dlfix.h"
-
-int plugin_main( void ) {
- lua_State* L = luaL_newstate();
- luaL_openlibs( L );
-#if 0
- MOON_DLFIX();
-#endif
- if( luaL_dofile( L, "test.lua" ) ) {
- fprintf( stderr, "%s\n", lua_tostring( L, 1 ) );
- lua_close( L );
- return EXIT_FAILURE;
- }
- lua_close( L );
- return EXIT_SUCCESS;
-}
-
diff --git a/framework/3rd/moon/examples/plugin.h b/framework/3rd/moon/examples/plugin.h
deleted file mode 100644
index 64c546f..0000000
--- a/framework/3rd/moon/examples/plugin.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef PLUGIN_H_
-#define PLUGIN_H_
-
-#define PLUGIN "plugin_main"
-typedef int (*plugin)( void );
-
-#endif /* PLUGIN_H_ */
-
diff --git a/framework/3rd/moon/examples/sofix.c b/framework/3rd/moon/examples/sofix.c
deleted file mode 100644
index 0a149de..0000000
--- a/framework/3rd/moon/examples/sofix.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#define _GNU_SOURCE
-#include "moon_dlfix.h"
-
-/* declaration of lua_State as an opaque type */
-struct lua_State;
-typedef struct lua_State lua_State;
-
-#ifndef EXPORT
-#define EXPORT extern
-#endif
-
-EXPORT int luaopen_sofix( lua_State* L ) {
- (void)L;
- MOON_DLFIX();
- return 0;
-}
-
diff --git a/framework/3rd/moon/examples/stkex.c b/framework/3rd/moon/examples/stkex.c
deleted file mode 100644
index acb0312..0000000
--- a/framework/3rd/moon/examples/stkex.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include
-#include
-#include
-#include "moon.h"
-
-static int somefunc( lua_State* L ) {
- moon_stack_assert( L, "s", "ds", "t" );
- lua_pushinteger( L, lua_gettop( L ) );
- return 1;
-}
-
-int luaopen_stkex( lua_State* L ) {
- luaL_Reg const stkex_funcs[] = {
- { "somefunc", somefunc },
- { NULL, NULL }
- };
-#if LUA_VERSION_NUM < 502
- luaL_register( L, "stkex", stkex_funcs );
-#else
- luaL_newlib( L, stkex_funcs );
-#endif
- return 1;
-}
diff --git a/framework/3rd/moon/examples/test.lua b/framework/3rd/moon/examples/test.lua
deleted file mode 100755
index 58301be..0000000
--- a/framework/3rd/moon/examples/test.lua
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/lua
-
-package.cpath = "./?.so;../?.so;.\\?.dll;..\\?.dll"
-require( "sofix" )
-
-local objex = require( "objex" )
-local flgex = require( "flgex" )
-local stkex = require( "stkex" )
-
-
-print( _VERSION )
-do
- print( ("="):rep( 70 ) )
- print( "[ objex test ]" )
- local m = objex.getAmethods()
- print( type( m ) )
- if type( m ) == "table" then
- for k,v in pairs( m ) do
- print( k, v )
- end
- end
- local a = objex.newA()
- print( a, a.tag )
- a:printme()
- local b = a.b
- print( a.b, b, a.c, b.f )
- b.f = 1.0
- print( pcall( function() b:printme() end ) )
- a:printme()
- a:switch()
- print( pcall( function() b:printme() end ) )
- print( a, a.tag )
- a:printme()
- local c = a.c
- print( a.c, c, a.b )
- c:printme()
- local d = c.d
- print( c.d, d, d.x, d.y )
- d:printme()
- d.x = 5
- d.y = 10
- print( d, d.x, d.y )
- d:printme()
- a:switch()
- print( pcall( d.printme, d ) )
- a:switch()
- d:printme()
- c:close()
- print( pcall( d.printme, d ) )
- local d2 = objex.getD()
- print( d2, d2.x, d2.y )
- d2:printme()
- local d3 = objex.makeD( 100, 200 )
- print( d3, d3.x, d3.y )
- d3:printme()
- local d4 = objex.newD()
- print( d4, d4.x, d4.y )
- d4:printme()
- local c2 = objex.newC()
- c2.d.x = 22
- c2.d.y = 44
- d2.x = 4
- d2.y = 8
- print( c2 )
- c2:printme()
- c2.d = d2
- c2:printme()
- c2:printmeD()
- d2:printme()
- local methods = objex.derive( "Derived", "D" )
- function methods:func( ... )
- print( self, self.a, ... )
- end
- local function makeDerived()
- local d = objex.newD()
- d.a = "a"
- return objex.downcast( d, "Derived" )
- end
- local x = makeDerived()
- x.x = 1
- x.y = 2
- x:printme()
- x:vcall( 1, 2, 3 )
-end
-collectgarbage()
-
-
-do
- print( ("="):rep( 70 ) )
- print( "[ flgex test ]" )
- local m = flgex.getXmethods()
- print( type( m ) )
- if type( m ) == "table" then
- for k,v in pairs( m ) do
- print( k, v )
- end
- end
- local flags = flgex.NULL + flgex.ONE + flgex.TWO
- print( flags )
---[[
- print( "bitops work(1):", flgex.NULL | flgex.ONE | flgex.TWO == flags )
- print( "bitops work(2):", flags & ~flgex.ONE == flgex.TWO )
---]]
- print( "flags contains flgex.ONE?", flags( flgex.ONE ) )
- print( "flags contains flgex.TWO?", flags( flgex.TWO ) )
- flags = flags - flgex.ONE
- print( "flags contains flgex.ONE?", flags( flgex.ONE ) )
- print( "flags contains flgex.TWO?", flags( flgex.TWO ) )
- flags = flags - flgex.TWO
- print( "flags contains flgex.ONE?", flags( flgex.ONE ) )
- print( "flags contains flgex.TWO?", flags( flgex.TWO ) )
- print( "same and identical:", flags == flgex.NULL, flags, flgex.NULL )
- flags = (flgex.THREE + flgex.FOUR) - flgex.FOUR
- print( "same but not identical:", flags == flgex.THREE, flags, flgex.THREE )
- print( "better error message for mismatched types:" )
- print( pcall( function() local wrong = flgex.ONE + flgex.THREE end ) )
-end
-
-
-do
- print( ("="):rep( 70 ) )
- print( "[ stkex test ]" )
- print( pcall( stkex.somefunc, "hello", 123, {} ) )
- print()
- print( pcall( stkex.somefunc, "hello", "world", {} ) )
- print()
- print( pcall( stkex.somefunc, {} ) )
- print()
- print( pcall( stkex.somefunc, true ) )
- print()
- print( pcall( stkex.somefunc, "hel\001lo\n", nil, {} ) )
- print()
- print( pcall( stkex.somefunc, nil, nil, nil ) )
-end
-
diff --git a/framework/3rd/moon/moon.c b/framework/3rd/moon/moon.c
deleted file mode 100644
index a3320f1..0000000
--- a/framework/3rd/moon/moon.c
+++ /dev/null
@@ -1,1349 +0,0 @@
-/* Copyright 2013-2020 Philipp Janda
- *
- * You may do anything with this work that copyright law would normally
- * restrict, so long as you retain the above notice(s) and this license
- * in all redistributed copies and derived works. There is no warranty.
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include "moon.h"
-
-/* don't compile it again if it's already included via moon.h */
-#ifndef MOON_C_
-#define MOON_C_
-
-#if LUA_VERSION_NUM < 502
-MOON_API int moon_absindex(lua_State *L, int i)
-{
- if (i < 0 && i > LUA_REGISTRYINDEX)
- i += lua_gettop(L) + 1;
- return i;
-}
-#endif
-
-/* struct that is part of some moon objects (those created via
- * `moon_newfield`) and contains a function pointer and a data pointer
- * that can be used to check whether the object is still valid. The
- * check is done automatically in `moon_{check,test}object`, and is
- * primarily needed to safely support tagged unions. */
-typedef struct moon_object_vcheck_
-{
- int (*check)(void *);
- void *tagp;
- struct moon_object_vcheck_ *next; /* linked list */
-} moon_object_vcheck_;
-
-/* For keeping memory consumption as low as possible multiple C
- * values might be stored side-by-side in the same memory block, and
- * we have to figure out the alignment to use for those values. */
-typedef union
-{
- lua_Number n;
- double d;
- lua_Integer i;
- long l;
- size_t s;
- void *p;
- void (*fp)(void);
-} moon_object_alignment_u_;
-
-/* Newer versions of C and C++ have a way to figure out alignment
- * built into the language, and we use those if available. There's
- * also a fallback implementation for older versions. */
-#ifndef MOON_ALIGNOF_
-#if defined(__cplusplus) && __cplusplus >= 201103L
-/* alignof is an operator in newer C++ versions */
-#define MOON_ALIGNOF_(_t) alignof(_t)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
-/* newer C versions have it in stdalign.h */
-#include
-#define MOON_ALIGNOF_(_t) alignof(_t)
-#elif defined(__cplusplus)
-/* Same as below, but MSVC++ has problems with that code, so we use a
- * template instead of a type-as-expression. */
-template
-struct moon_alignof_struct_
-{
- char _1;
- T _2;
-};
-#define MOON_ALIGNOF_(_t) \
- (offsetof(moon_alignof_struct_<_t>, _2) > sizeof(_t) \
- ? sizeof(_t) \
- : offsetof(moon_alignof_struct_<_t>, _2))
-#else
-/* Calculate the alignment ourselves. This may give smaller values
- * than using `sizeof( _t )` which is also a portable solution. */
-#define MOON_ALIGNOF_(_t) \
- (offsetof( \
- struct \
- { \
- char _1; \
- _t _2; \
- }, \
- _2) > sizeof(_t) \
- ? sizeof(_t) \
- : offsetof( \
- struct \
- { \
- char _1; \
- _t _2; \
- }, \
- _2))
-#endif
-#endif
-
-#define MOON_OBJ_ALIGNMENT_ MOON_ALIGNOF_(moon_object_alignment_u_)
-#define MOON_PTR_ALIGNMENT_ MOON_ALIGNOF_(void *)
-#define MOON_GCF_ALIGNMENT_ MOON_ALIGNOF_(moon_object_destructor)
-#define MOON_VCK_ALIGNMENT_ MOON_ALIGNOF_(moon_object_vcheck_)
-#define MOON_ROUNDTO_(_s, _a) ((((_s) + (_a)-1) / (_a)) * (_a))
-#define MOON_PTR_(_p, _o) ((void *)(((char *)(_p)) + (_o)))
-
-/* Raise properly formatted argument error messages. */
-static int moon_type_error_(lua_State *L, int i, char const *t1,
- char const *t2)
-{
- char const *msg = lua_pushfstring(L, "%s expected, got %s", t1, t2);
- return luaL_argerror(L, i, msg);
-}
-
-static int moon_type_error_invalid_(lua_State *L, int i,
- char const *tname)
-{
- char const *msg = lua_pushfstring(L, "invalid '%s' object", tname);
- return luaL_argerror(L, i, msg);
-}
-
-static int moon_type_error_version_(lua_State *L, int i)
-{
- char const *msg = lua_pushfstring(L, "not a moon %d.%d object",
- MOON_VERSION_MAJOR,
- MOON_VERSION_MINOR);
- return luaL_argerror(L, i, msg);
-}
-
-static int moon_is_property(char const *name)
-{
- return name[0] == '.';
-}
-static int moon_is_meta(char const *name)
-{
- return name[0] == '_' && name[1] == '_';
-}
-static int moon_is_method(char const *name)
-{
- return !moon_is_meta(name) && !moon_is_property(name);
-}
-
-/* Default implementation of a __tostring metamethod for moon objects
- * which displays the type name and memory address. */
-MOON_LLINKAGE_BEGIN
-static int moon_object_default_tostring_(lua_State *L)
-{
- void *ptr = lua_touserdata(L, 1);
- char const *name = lua_tostring(L, lua_upvalueindex(1));
- char const *basename = strrchr(name, '.');
- if (basename != NULL)
- name = basename + 1;
- lua_pushfstring(L, "[%s]: %p", name, ptr);
- return 1;
-}
-MOON_LLINKAGE_END
-
-/* Run the destructor and mark the object as invalid/destroyed. */
-static void moon_object_run_destructor_(moon_object_header *h)
-{
- if (h->cleanup_offset > 0 && (h->flags & MOON_OBJECT_IS_VALID))
- {
- void *p = MOON_PTR_(h, h->object_offset);
- moon_object_destructor *gc = NULL;
- gc = (moon_object_destructor *)MOON_PTR_(h, h->cleanup_offset);
- if (h->flags & MOON_OBJECT_IS_POINTER)
- p = *((void **)p);
- if (*gc != 0 && p != NULL)
- (*gc)(p);
- }
- h->flags &= ~MOON_OBJECT_IS_VALID;
-}
-
-/* Common __gc metamethod for all moon objects. The actual finalizer
- * function is stored in the userdata to support different lifetimes.
- */
-MOON_LLINKAGE_BEGIN
-static int moon_object_default_gc_(lua_State *L)
-{
- moon_object_header *h = (moon_object_header *)lua_touserdata(L, 1);
- moon_object_run_destructor_(h);
- return 0;
-}
-MOON_LLINKAGE_END
-
-static int moon_index_dispatch_methods_(lua_State *L)
-{
- if (lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE)
- {
- lua_pushvalue(L, 2); /* duplicate key */
- lua_rawget(L, lua_upvalueindex(1));
- if (!lua_isnil(L, -1))
- return 1;
- lua_pop(L, 1);
- }
- return 0;
-}
-
-static int moon_index_dispatch_properties_(lua_State *L)
-{
- if (lua_type(L, lua_upvalueindex(2)) == LUA_TTABLE)
- {
- lua_pushvalue(L, 2); /* duplicate key */
- lua_rawget(L, lua_upvalueindex(2));
- if (!lua_isnil(L, -1))
- {
- lua_pushvalue(L, 1);
- lua_call(L, 1, 1);
- return 1;
- }
- lua_pop(L, 1);
- }
- return 0;
-}
-
-static int moon_index_dispatch_function_(lua_State *L)
-{
- if (lua_type(L, lua_upvalueindex(3)) == LUA_TFUNCTION)
- {
- lua_pushvalue(L, lua_upvalueindex(3));
- lua_pushvalue(L, 1);
- lua_pushvalue(L, 2);
- lua_call(L, 2, 1);
- return 1;
- }
- return 0;
-}
-
-static int moon_newindex_dispatch_properties_(lua_State *L)
-{
- if (lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE)
- {
- lua_pushvalue(L, 2); /* duplicate key */
- lua_rawget(L, lua_upvalueindex(1));
- if (lua_isfunction(L, -1))
- {
- lua_pushvalue(L, 1);
- lua_pushvalue(L, 2);
- lua_pushvalue(L, 3);
- lua_call(L, 3, 0);
- return 1;
- }
- lua_pop(L, 1);
- }
- return 0;
-}
-
-static int moon_newindex_dispatch_function_(lua_State *L)
-{
- if (lua_type(L, lua_upvalueindex(2)) == LUA_TFUNCTION)
- {
- lua_pushvalue(L, lua_upvalueindex(2));
- lua_pushvalue(L, 1);
- lua_pushvalue(L, 2);
- lua_pushvalue(L, 3);
- lua_call(L, 3, 0);
- return 1;
- }
- return 0;
-}
-
-/* Check the methods and properties tables for a given key and then
- * (if unsuccessful) call the registered C function for looking up
- * properties. */
-MOON_LLINKAGE_BEGIN
-static int moon_index_dispatch_(lua_State *L)
-{
- if (!moon_index_dispatch_methods_(L) &&
- !moon_index_dispatch_properties_(L) &&
- !moon_index_dispatch_function_(L))
- lua_pushnil(L);
- return 1;
-}
-
-static int moon_newindex_dispatch_(lua_State *L)
-{
- if (!moon_newindex_dispatch_properties_(L) &&
- !moon_newindex_dispatch_function_(L))
- luaL_error(L, "attempt to set invalid field");
- return 0;
-}
-MOON_LLINKAGE_END
-
-static lua_CFunction moon_getf_(lua_State *L, char const *name,
- lua_CFunction def)
-{
- lua_CFunction f = 0;
- lua_pushliteral(L, "__moon");
- lua_rawget(L, LUA_REGISTRYINDEX);
- if (lua_type(L, -1) != LUA_TTABLE)
- {
- lua_pop(L, 1);
- lua_newtable(L);
- lua_pushliteral(L, "__moon");
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
- lua_getfield(L, -1, name);
- f = lua_tocfunction(L, -1);
- lua_pop(L, 1);
- if (!f)
- {
- f = def;
- lua_pushcfunction(L, def);
- lua_setfield(L, -2, name);
- }
- lua_pop(L, 1);
- return f;
-}
-
-static void moon_pushreg_(lua_State *L, luaL_Reg const funcs[],
- int (*predicate)(char const *),
- int nups, int firstupvalue, int skip)
-{
- if (funcs != NULL)
- {
- lua_newtable(L);
- for (; funcs->func; ++funcs)
- {
- if (predicate(funcs->name))
- {
- int i = 0;
- for (i = 0; i < nups; ++i)
- lua_pushvalue(L, firstupvalue + i);
- lua_pushcclosure(L, funcs->func, nups);
- lua_setfield(L, -2, funcs->name + skip);
- }
- }
- }
- else
- lua_pushnil(L);
-}
-
-static void moon_pushfunction_(lua_State *L, lua_CFunction func,
- int nups, int firstupvalue)
-{
- if (func != 0)
- {
- int i = 0;
- for (i = 0; i < nups; ++i)
- lua_pushvalue(L, firstupvalue + i);
- lua_pushcclosure(L, func, nups);
- }
- else
- lua_pushnil(L);
-}
-
-/* Depending on the availability of a methods table and/or a C
- * function for looking up properties this function creates an __index
- * metamethod (function or table). */
-static void moon_makeindex_(lua_State *L, luaL_Reg const methods[],
- luaL_Reg const properties[],
- lua_CFunction pindex, int nups)
-{
- int firstupvalue = lua_gettop(L) + 1 - nups;
- if (!properties && !pindex)
- { /* methods only (maybe) */
- moon_pushreg_(L, methods, moon_is_method, nups, firstupvalue, 0);
- if (nups > 0)
- {
- lua_replace(L, firstupvalue);
- lua_pop(L, nups - 1);
- }
- }
- else if (!methods && !properties)
- { /* index function only */
- lua_pushcclosure(L, pindex, nups);
- }
- else
- {
- lua_CFunction dispatch = moon_getf_(L, "index", moon_index_dispatch_);
- moon_pushreg_(L, methods, moon_is_method, nups, firstupvalue, 0);
- moon_pushreg_(L, properties, moon_is_property, nups, firstupvalue, 1);
- moon_pushfunction_(L, pindex, nups, firstupvalue);
- lua_pushcclosure(L, dispatch, 3);
- if (nups > 0)
- {
- lua_replace(L, firstupvalue);
- lua_pop(L, nups - 1);
- }
- }
-}
-
-static void moon_makenewindex_(lua_State *L, luaL_Reg const properties[],
- lua_CFunction pnewindex, int nups)
-{
- if (!properties && !pnewindex)
- {
- lua_pop(L, nups);
- lua_pushnil(L);
- }
- else if (!properties)
- {
- lua_pushcclosure(L, pnewindex, nups);
- }
- else
- {
- int firstupvalue = lua_gettop(L) + 1 - nups;
- lua_CFunction dispatch = moon_getf_(L, "newindex", moon_newindex_dispatch_);
- moon_pushreg_(L, properties, moon_is_property, nups, firstupvalue, 1);
- moon_pushfunction_(L, pnewindex, nups, firstupvalue);
- lua_pushcclosure(L, dispatch, 2);
- if (nups > 0)
- {
- lua_replace(L, firstupvalue);
- lua_pop(L, nups - 1);
- }
- }
-}
-
-/* Type names used by the moon toolkit must not start with a double
- * underscore, because they might be used as keys in the metatable. */
-static void moon_check_tname_(lua_State *L, char const *tname)
-{
- if (tname == NULL || tname[0] == '_')
- luaL_error(L, "invalid type name: '%s'", tname ? tname : "NULL");
-}
-
-MOON_API void moon_defobject(lua_State *L, char const *tname,
- size_t sz, luaL_Reg const *methods,
- int nups)
-{
- int has_methods = 0;
- int has_properties = 0;
- lua_CFunction index = 0;
- lua_CFunction newindex = 0;
- moon_check_tname_(L, tname);
- luaL_checkstack(L, 2 * nups + 4, "moon_defobject");
- /* we don't use luaL_newmetatable to make sure that we never have a
- * half-constructed metatable in the registry! */
- luaL_getmetatable(L, tname);
- if (!lua_isnil(L, -1))
- luaL_error(L, "type '%s' is already defined", tname);
- lua_pop(L, 1);
- lua_newtable(L);
- lua_pushstring(L, tname);
- lua_pushcclosure(L, moon_object_default_tostring_, 1);
- lua_setfield(L, -2, "__tostring");
- if (methods != NULL)
- {
- luaL_Reg const *l = methods;
- int i = 0;
- for (; l->func != NULL; ++l)
- {
- if (moon_is_meta(l->name))
- {
- int is_index = 0 == strcmp(l->name + 2, "index");
- int is_newindex = 0 == strcmp(l->name + 2, "newindex");
- if (!is_index && !is_newindex)
- {
- for (i = 0; i < nups; ++i)
- lua_pushvalue(L, -nups - 1);
- lua_pushcclosure(L, l->func, nups);
- lua_setfield(L, -2, l->name);
- }
- else if (is_index) /* handle __index later */
- index = l->func;
- else /* handle __newindex later */
- newindex = l->func;
- }
- else if (moon_is_property(l->name))
- {
- has_properties = 1;
- }
- else
- has_methods = 1;
- }
- }
- if (has_methods || has_properties || index)
- {
- int i = 0;
- for (i = 0; i < nups; ++i)
- lua_pushvalue(L, -nups - 1);
- moon_makeindex_(L, has_methods ? methods : NULL,
- has_properties ? methods : NULL, index, nups);
- lua_setfield(L, -2, "__index");
- }
- if (has_properties || newindex)
- {
- int i = 0;
- for (i = 0; i < nups; ++i)
- lua_pushvalue(L, -nups - 1);
- moon_makenewindex_(L, methods, newindex, nups);
- lua_setfield(L, -2, "__newindex");
- }
- lua_pushboolean(L, 0);
- lua_setfield(L, -2, "__metatable");
- lua_pushstring(L, tname);
- lua_setfield(L, -2, "__name");
- lua_pushcfunction(L, moon_object_default_gc_);
- lua_pushvalue(L, -1);
- lua_setfield(L, -3, "__gc");
- lua_setfield(L, -2, "__close");
- lua_pushinteger(L, MOON_VERSION);
- lua_setfield(L, -2, "__moon_version");
- lua_pushinteger(L, (lua_Integer)sz);
- lua_setfield(L, -2, "__moon_size");
- lua_setfield(L, LUA_REGISTRYINDEX, tname);
- lua_pop(L, nups);
-}
-
-/* Verify that the value at the stack top is the metatable for a moon
- * object type. */
-static void moon_check_metatable_(lua_State *L, char const *tname)
-{
- if (!lua_istable(L, -1))
- luaL_error(L, "no metatable for type '%s' defined", tname);
- lua_getfield(L, -1, "__moon_version");
- if (lua_tointeger(L, -1) != MOON_VERSION)
- luaL_error(L, "'%s' is not a moon %d.%d object type", tname,
- MOON_VERSION_MAJOR, MOON_VERSION_MINOR);
- lua_pop(L, 1);
-}
-
-/* Pushes the metatable for the given type onto the Lua stack, and
- * makes sure that the given type is a moon object type. */
-static void moon_push_metatable_(lua_State *L, char const *tname)
-{
- moon_check_tname_(L, tname);
- luaL_getmetatable(L, tname);
- moon_check_metatable_(L, tname);
-}
-
-MOON_API void *moon_newobject(lua_State *L, char const *tname,
- void (*gc)(void *))
-{
- moon_object_header *obj = NULL;
- size_t off1 = 0;
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4116)
-#endif
- size_t off2 = MOON_ROUNDTO_(sizeof(moon_object_header),
- MOON_OBJ_ALIGNMENT_);
- size_t sz = 0;
- luaL_checkstack(L, 2, "moon_newobject");
- moon_push_metatable_(L, tname);
- lua_getfield(L, -1, "__moon_size");
- sz = lua_tointeger(L, -1);
- lua_pop(L, 1);
- if (sz == 0)
- luaL_error(L, "type '%s' is incomplete (size is 0)", tname);
- if (gc != 0)
- {
- off1 = MOON_ROUNDTO_(sizeof(moon_object_header),
- MOON_GCF_ALIGNMENT_);
- off2 = MOON_ROUNDTO_(off1 + sizeof(moon_object_destructor),
- MOON_OBJ_ALIGNMENT_);
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
- }
- obj = (moon_object_header *)lua_newuserdata(L, sz + off2);
- if (off1 > 0)
- {
- moon_object_destructor *cl = NULL;
- cl = (moon_object_destructor *)MOON_PTR_(obj, off1);
- *cl = gc;
- }
- obj->cleanup_offset = off1;
- obj->object_offset = off2;
- obj->vcheck_offset = 0;
- obj->flags = MOON_OBJECT_IS_VALID;
- lua_insert(L, -2);
- lua_setmetatable(L, -2);
- return MOON_PTR_(obj, off2);
-}
-
-MOON_API void **moon_newpointer(lua_State *L, char const *tname,
- void (*gc)(void *))
-{
- moon_object_header *obj = NULL;
- void **p = NULL;
- size_t off1 = 0;
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4116)
-#endif
- size_t off2 = MOON_ROUNDTO_(sizeof(moon_object_header),
- MOON_PTR_ALIGNMENT_);
- luaL_checkstack(L, 2, "moon_newpointer");
- moon_push_metatable_(L, tname);
- if (gc != 0)
- {
- off1 = MOON_ROUNDTO_(sizeof(moon_object_header),
- MOON_GCF_ALIGNMENT_);
- off2 = MOON_ROUNDTO_(off1 + sizeof(moon_object_destructor),
- MOON_PTR_ALIGNMENT_);
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
- }
- obj = (moon_object_header *)lua_newuserdata(L, sizeof(void *) + off2);
- p = (void **)MOON_PTR_(obj, off2);
- *p = NULL;
- if (off1 > 0)
- {
- moon_object_destructor *cl = NULL;
- cl = (moon_object_destructor *)MOON_PTR_(obj, off1);
- *cl = gc;
- }
- obj->cleanup_offset = off1;
- obj->object_offset = off2;
- obj->vcheck_offset = 0;
- obj->flags = MOON_OBJECT_IS_VALID | MOON_OBJECT_IS_POINTER;
- lua_insert(L, -2);
- lua_setmetatable(L, -2);
- return p;
-}
-
-MOON_API void **moon_newfield(lua_State *L, char const *tname,
- int idx, int (*isvalid)(void *),
- void *tagp)
-{
- moon_object_header *obj = NULL;
- moon_object_vcheck_ *nextcheck = NULL;
- void **p = NULL;
- size_t off1 = 0;
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4116)
-#endif
- size_t off2 = MOON_ROUNDTO_(sizeof(moon_object_header),
- MOON_PTR_ALIGNMENT_);
- luaL_checkstack(L, 3, "moon_newfield");
- if (idx != 0)
- {
- moon_object_header *h = (moon_object_header *)lua_touserdata(L, idx);
- idx = moon_absindex(L, idx);
- if (h != NULL && lua_getmetatable(L, idx))
- {
- lua_getfield(L, -1, "__moon_version");
- if (lua_tointeger(L, -1) == MOON_VERSION)
- {
- if (h->vcheck_offset > 0)
- {
- moon_object_vcheck_ *vc = NULL;
- vc = (moon_object_vcheck_ *)MOON_PTR_(h, h->vcheck_offset);
- if (isvalid == 0)
- { /* inherit vcheck from idx object */
- isvalid = vc->check;
- tagp = vc->tagp;
- nextcheck = vc->next;
- }
- else /* add it to the chain */
- nextcheck = vc;
- }
- }
- lua_pop(L, 2);
- }
- }
- moon_push_metatable_(L, tname);
- if (isvalid != 0)
- {
- off1 = MOON_ROUNDTO_(sizeof(moon_object_header),
- MOON_VCK_ALIGNMENT_);
- off2 = MOON_ROUNDTO_(off1 + sizeof(moon_object_vcheck_),
- MOON_PTR_ALIGNMENT_);
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
- }
- obj = (moon_object_header *)lua_newuserdata(L, sizeof(void *) + off2);
- p = (void **)MOON_PTR_(obj, off2);
- *p = NULL;
- obj->vcheck_offset = off1;
- obj->object_offset = off2;
- obj->cleanup_offset = 0;
- obj->flags = MOON_OBJECT_IS_VALID | MOON_OBJECT_IS_POINTER;
- if (off1 > 0)
- {
- moon_object_vcheck_ *vc = NULL;
- vc = (moon_object_vcheck_ *)MOON_PTR_(obj, off1);
- vc->check = isvalid;
- vc->tagp = tagp;
- vc->next = nextcheck;
- }
- lua_insert(L, -2);
- lua_setmetatable(L, -2);
- if (idx != 0)
- {
- lua_newtable(L);
- lua_pushvalue(L, idx);
- lua_rawseti(L, -2, 1);
-#if LUA_VERSION_NUM < 502
- lua_setfenv(L, -2);
-#else
- lua_setuservalue(L, -2);
-#endif
- }
- return p;
-}
-
-MOON_API int moon_getmethods(lua_State *L, char const *tname)
-{
- int t = 0;
- luaL_checkstack(L, 2, "moon_getmethods");
- moon_push_metatable_(L, tname);
- lua_getfield(L, -1, "__index");
- lua_replace(L, -2);
- t = lua_type(L, -1);
- if (t == LUA_TTABLE)
- return t;
- else if (t == LUA_TFUNCTION)
- {
- lua_CFunction dispatch = moon_getf_(L, "index",
- moon_index_dispatch_);
- if (lua_tocfunction(L, -1) == dispatch &&
- lua_getupvalue(L, -1, 1) != NULL)
- {
- lua_replace(L, -2);
- if (lua_type(L, -1) == LUA_TTABLE)
- return LUA_TTABLE;
- }
- }
- lua_pop(L, 1);
- return LUA_TNIL;
-}
-
-MOON_API void moon_killobject(lua_State *L, int idx)
-{
- moon_object_header *h = (moon_object_header *)lua_touserdata(L, idx);
- luaL_checkstack(L, 2, "moon_killobject");
- if (h == NULL || !lua_getmetatable(L, idx))
- moon_type_error_version_(L, idx);
- lua_getfield(L, -1, "__moon_version");
- if (lua_tointeger(L, -1) != MOON_VERSION)
- moon_type_error_version_(L, idx);
- lua_pop(L, 2);
- moon_object_run_destructor_(h);
-}
-
-MOON_API void moon_defcast(lua_State *L, char const *tname1,
- char const *tname2,
- moon_object_cast cast)
-{
- luaL_checkstack(L, 2, "moon_defcast");
- moon_push_metatable_(L, tname1);
- moon_check_tname_(L, tname2);
- lua_pushcfunction(L, (lua_CFunction)(void (*)(void))cast);
- lua_setfield(L, -2, tname2);
- lua_pop(L, 1);
-}
-
-/* Validates a chain of vcheck objects. The chain won't be long, so
- * a recursive approach should be fine! */
-static int moon_validate_vcheck_(moon_object_vcheck_ const *vc)
-{
- if (vc->next != NULL)
- return moon_validate_vcheck_(vc->next) &&
- (vc->check == 0 || vc->check(vc->tagp));
- else
- return vc->check == 0 || vc->check(vc->tagp);
-}
-
-MOON_API void *moon_checkobject(lua_State *L, int idx,
- char const *tname)
-{
- moon_object_header *h = (moon_object_header *)lua_touserdata(L, idx);
- void *p = NULL;
- int res = 0;
- moon_object_cast cast = 0;
- moon_check_tname_(L, tname);
- luaL_checkstack(L, 3, "moon_checkobject");
- idx = moon_absindex(L, idx);
- if (h == NULL)
- moon_type_error_(L, idx, tname, luaL_typename(L, idx));
- if (lua_islightuserdata(L, idx))
- moon_type_error_(L, idx, tname, "lightuserdata");
- if (!lua_getmetatable(L, idx))
- moon_type_error_(L, idx, tname, "userdata");
- lua_getfield(L, -1, "__moon_version");
- if (lua_tointeger(L, -1) != MOON_VERSION)
- {
- lua_pop(L, 2);
- moon_type_error_version_(L, idx);
- }
- lua_pop(L, 1);
- luaL_getmetatable(L, tname);
- res = lua_rawequal(L, -1, -2);
- lua_pop(L, 1);
- if (!res)
- {
- lua_getfield(L, -1, tname);
- cast = (moon_object_cast)(void (*)(void))lua_tocfunction(L, -1);
- lua_pop(L, 1);
- if (cast == 0)
- {
- char const *name = NULL;
- lua_getfield(L, -1, "__name");
- name = lua_tostring(L, -1);
- moon_type_error_(L, idx, tname, name ? name : "userdata");
- }
- }
- lua_pop(L, 1);
- if (!(h->flags & MOON_OBJECT_IS_VALID))
- moon_type_error_invalid_(L, idx, tname);
- if (h->vcheck_offset > 0)
- {
- moon_object_vcheck_ *vc = NULL;
- vc = (moon_object_vcheck_ *)MOON_PTR_(h, h->vcheck_offset);
- if (!moon_validate_vcheck_(vc))
- moon_type_error_invalid_(L, idx, tname);
- }
- p = MOON_PTR_(h, h->object_offset);
- if (h->flags & MOON_OBJECT_IS_POINTER)
- p = *((void **)p);
- if (p == NULL)
- moon_type_error_invalid_(L, idx, tname);
- if (cast != 0)
- {
- p = cast(p);
- if (p == NULL)
- moon_type_error_invalid_(L, idx, tname);
- }
- return p;
-}
-
-MOON_API void *moon_testobject(lua_State *L, int idx,
- char const *tname)
-{
- moon_object_header *h = (moon_object_header *)lua_touserdata(L, idx);
- void *p = NULL;
- int res = 0;
- moon_object_cast cast = 0;
- moon_check_tname_(L, tname);
- luaL_checkstack(L, 2, "moon_testobject");
- if (h == NULL || !lua_getmetatable(L, idx))
- return NULL;
- lua_getfield(L, -1, "__moon_version");
- if (lua_tointeger(L, -1) != MOON_VERSION)
- {
- lua_pop(L, 2);
- return NULL;
- }
- lua_pop(L, 1);
- luaL_getmetatable(L, tname);
- res = lua_rawequal(L, -1, -2);
- lua_pop(L, 1);
- if (!res)
- {
- lua_getfield(L, -1, tname);
- cast = (moon_object_cast)(void (*)(void))lua_tocfunction(L, -1);
- lua_pop(L, 2);
- if (cast == 0)
- return NULL;
- }
- else
- lua_pop(L, 1);
- if (!(h->flags & MOON_OBJECT_IS_VALID))
- return NULL;
- if (h->vcheck_offset > 0)
- {
- moon_object_vcheck_ *vc = NULL;
- vc = (moon_object_vcheck_ *)MOON_PTR_(h, h->vcheck_offset);
- if (!moon_validate_vcheck_(vc))
- return NULL;
- }
- p = MOON_PTR_(h, h->object_offset);
- if (h->flags & MOON_OBJECT_IS_POINTER)
- p = *((void **)p);
- if (cast != 0)
- p = cast(p);
- return p;
-}
-
-static void *moon_cast_id_(void *p)
-{
- return p;
-}
-
-static void moon_copy_table_(lua_State *L, int src, int dst)
-{
- src = moon_absindex(L, src);
- dst = moon_absindex(L, dst);
- lua_pushnil(L);
- while (lua_next(L, src))
- {
- lua_pushvalue(L, -2); /* duplicate key */
- lua_pushvalue(L, -2); /* duplicate value */
- lua_rawset(L, dst);
- lua_pop(L, 1); /* pop value */
- }
-}
-
-MOON_LLINKAGE_BEGIN
-MOON_API int moon_derive(lua_State *L)
-{
- char const *newtype = luaL_checkstring(L, 1);
- char const *oldtype = luaL_checkstring(L, 2);
- int t = 0;
- lua_settop(L, 2);
- moon_check_tname_(L, newtype);
- lua_pushvalue(L, 1);
- lua_rawget(L, LUA_REGISTRYINDEX);
- luaL_argcheck(L, lua_isnil(L, -1), 1,
- "attempt to redefine type");
- lua_pop(L, 1);
- lua_pushvalue(L, 2);
- lua_rawget(L, LUA_REGISTRYINDEX); /* 3: old metatable */
- moon_check_metatable_(L, oldtype);
- /* clone metatable */
- lua_newtable(L); /* 4: new metatable */
- moon_copy_table_(L, 3, 4);
- /* replace __tostring */
- lua_pushvalue(L, 1);
- lua_pushcclosure(L, moon_object_default_tostring_, 1);
- lua_setfield(L, 4, "__tostring");
- /* add cast to old type */
- lua_pushvalue(L, 2);
- lua_pushcfunction(L, moon_getf_(L, "cast",
- (lua_CFunction)(void (*)(void))moon_cast_id_));
- lua_rawset(L, 4);
- /* replace __index metamethod */
- lua_pushliteral(L, "__index");
- lua_rawget(L, 4); /* 5: __index metamethod */
- t = lua_type(L, 5);
- lua_newtable(L); /* 6: new methods table */
- lua_pushliteral(L, "__index"); /* 7: string "__index" */
- if (t == LUA_TTABLE)
- {
- moon_copy_table_(L, 5, 6);
- lua_pushvalue(L, 6); /* 8: new methods table */
- }
- else if (t == LUA_TFUNCTION)
- {
- lua_CFunction dispatch = moon_getf_(L, "index",
- moon_index_dispatch_);
- if (lua_tocfunction(L, 5) == dispatch)
- {
- lua_getupvalue(L, 5, 1); /* 8: old methods table */
- if (lua_istable(L, -1))
- moon_copy_table_(L, -1, 6);
- lua_pop(L, 1);
- lua_pushvalue(L, 6); /* 8: new methods table */
- lua_getupvalue(L, 5, 2); /* 9: properties */
- lua_getupvalue(L, 5, 3); /* 10: index func */
- lua_pushcclosure(L, dispatch, 3); /* 8: dispatcher */
- }
- else
- {
- lua_pushvalue(L, 6); /* 8: new methods table */
- lua_pushnil(L); /* 9: no properties */
- lua_pushvalue(L, 5); /* 10: index func */
- lua_pushcclosure(L, dispatch, 3); /* 8: dispatcher */
- }
- }
- else
- lua_pushvalue(L, 6); /* 8: new methods table */
- lua_rawset(L, 4);
- /* register new type */
- lua_pushvalue(L, 1);
- lua_pushvalue(L, 4);
- lua_rawset(L, LUA_REGISTRYINDEX);
- return 1;
-}
-MOON_LLINKAGE_END
-
-MOON_LLINKAGE_BEGIN
-MOON_API int moon_downcast(lua_State *L)
-{
- void *h = lua_touserdata(L, 1);
- char const *tname = luaL_checkstring(L, 2);
- moon_object_cast cast = 0, id_cast = 0;
- lua_settop(L, 2);
- luaL_argcheck(L, h != NULL && lua_getmetatable(L, 1), 1,
- "object expected"); /* 3: metatable */
- luaL_argcheck(L, lua_istable(L, -1), 1, "object expected");
- lua_getfield(L, -1, "__moon_version");
- luaL_argcheck(L, lua_tointeger(L, -1) == MOON_VERSION, 1,
- "object expected");
- lua_pop(L, 1);
- moon_check_tname_(L, tname);
- lua_getfield(L, -1, "__name"); /* 4: __name */
- lua_pushvalue(L, 2);
- lua_rawget(L, LUA_REGISTRYINDEX); /* 5: metatable */
- moon_check_metatable_(L, tname);
- lua_pushvalue(L, 4);
- lua_rawget(L, 5); /* 6: cast function */
- cast = (moon_object_cast)(void (*)(void))lua_tocfunction(L, -1);
- id_cast = (moon_object_cast)(void (*)(void))moon_getf_(L, "cast", (lua_CFunction)(void (*)(void))moon_cast_id_);
- luaL_argcheck(L, cast == id_cast, 1, "invalid downcast");
- lua_pop(L, 1);
- lua_setmetatable(L, 1);
- lua_settop(L, 1);
- return 1;
-}
-MOON_LLINKAGE_END
-
-MOON_API lua_Integer moon_checkint(lua_State *L, int idx,
- lua_Integer low,
- lua_Integer high)
-{
- lua_Integer v = luaL_checkinteger(L, idx);
- int valid = (high < low) ? (low <= v || v <= high)
- : (low <= v && v <= high);
- if (!valid)
- {
- char const *msg = NULL;
-#if LUA_VERSION_NUM >= 503
- msg = lua_pushfstring(L, "value out of range [%I,%I]", low, high);
-#else
- if (low >= INT_MIN && low <= INT_MAX &&
- high >= INT_MIN && high <= INT_MAX)
- msg = lua_pushfstring(L, "value out of range [%d,%d]",
- (int)low, (int)high);
- else
- msg = lua_pushfstring(L, "value out of range [%f,%f]",
- (lua_Number)low, (lua_Number)high);
-#endif
- luaL_argerror(L, idx, msg);
- }
- return v;
-}
-
-MOON_API lua_Integer moon_optint(lua_State *L, int idx,
- lua_Integer low, lua_Integer high,
- lua_Integer def)
-{
- if (!lua_isnoneornil(L, idx))
- def = moon_checkint(L, idx, low, high);
- return def;
-}
-
-MOON_API int *moon_atexit(lua_State *L, lua_CFunction func)
-{
- int *flag = NULL;
- luaL_checkstack(L, 3, "moon_atexit");
- flag = (int *)lua_newuserdata(L, sizeof(int));
- *flag = 0;
- /* setmetatable( flag, { __gc = func } ) */
- lua_newtable(L);
- lua_pushcfunction(L, func);
- lua_setfield(L, -2, "__gc");
- lua_setmetatable(L, -2);
- /* registry[ flag ] = flag */
- lua_pushvalue(L, -1);
- lua_pushvalue(L, -2);
- lua_settable(L, LUA_REGISTRYINDEX);
- return flag;
-}
-
-MOON_API void moon_setuvfield(lua_State *L, int i, char const *key)
-{
- luaL_checkstack(L, 2, "moon_setuvfield");
-#if LUA_VERSION_NUM < 502
- lua_getfenv(L, i);
-#else
- lua_getuservalue(L, i);
-#endif
- if (!lua_istable(L, -1))
- luaL_error(L, "attempt to add to non-table uservalue");
- lua_pushvalue(L, -2);
- lua_setfield(L, -2, key);
- lua_pop(L, 2);
-}
-
-MOON_API int moon_getuvfield(lua_State *L, int i, char const *key)
-{
- luaL_checkstack(L, 2, "moon_getuvfield");
-#if LUA_VERSION_NUM < 502
- lua_getfenv(L, i);
-#else
- lua_getuservalue(L, i);
-#endif
- if (lua_istable(L, -1))
- {
- int t = 0;
- lua_getfield(L, -1, key);
- lua_replace(L, -2);
- t = lua_type(L, -1);
- if (t != LUA_TNIL)
- return t;
- }
- lua_pop(L, 1);
- return LUA_TNIL;
-}
-
-MOON_API void moon_getcache(lua_State *L, int index)
-{
- static char xyz = 0; /* used as a unique key */
- luaL_checkstack(L, 3, "moon_getcache");
- index = moon_absindex(L, index);
- lua_pushlightuserdata(L, &xyz);
- lua_rawget(L, index);
- if (!lua_istable(L, -1))
- {
- lua_pop(L, 1);
- lua_createtable(L, 0, 1);
- lua_pushliteral(L, "__mode");
- lua_pushliteral(L, "v");
- lua_rawset(L, -3);
- lua_pushvalue(L, -1);
- lua_setmetatable(L, -2);
- lua_pushlightuserdata(L, &xyz);
- lua_pushvalue(L, -2);
- lua_rawset(L, index);
- }
-}
-
-static int moon_check_type_(lua_State *L, int idx, char const *spec)
-{
- int t = lua_type(L, idx);
- while (*spec != '\0')
- {
- switch (*spec)
- {
- case 'n':
- if (t == LUA_TNIL)
- return 1;
- break;
- case 'b':
- if (t == LUA_TBOOLEAN)
- return 1;
- break;
- case 'l':
- if (t == LUA_TLIGHTUSERDATA)
- return 1;
- break;
- case 'i':
- if (t == LUA_TNUMBER
-#if LUA_VERSION_NUM >= 503
- && lua_isinteger(L, idx)
-#endif
- )
- return 1;
- break;
- case 'd':
- if (t == LUA_TNUMBER)
- return 1;
- break;
- case 's':
- if (t == LUA_TSTRING)
- return 1;
- break;
- case 't':
- if (t == LUA_TTABLE)
- return 1;
- break;
- case 'f':
- if (t == LUA_TFUNCTION)
- return 1;
- break;
- case 'u':
- if (t == LUA_TUSERDATA)
- return 1;
- break;
- case 'c':
- if (t == LUA_TTHREAD)
- return 1;
- break;
- case 'a':
- if (t != LUA_TNIL)
- return 1;
- break;
- }
- ++spec;
- }
- return 0;
-}
-
-static char const *moon_type2spec_(int t)
-{
- switch (t)
- {
- case LUA_TNONE:
- case LUA_TNIL:
- return "n";
- case LUA_TBOOLEAN:
- return "b";
- case LUA_TLIGHTUSERDATA:
- return "l";
- case LUA_TNUMBER:
- return "d";
- case LUA_TSTRING:
- return "s";
- case LUA_TTABLE:
- return "t";
- case LUA_TFUNCTION:
- return "f";
- case LUA_TUSERDATA:
- return "u";
- case LUA_TTHREAD:
- return "c";
- default:
- return "?";
- }
-}
-
-#define MOON_SEP_ \
- "######################################################################"
-
-MOON_API void moon_stack_assert_(lua_State *L, char const *file,
- int line, char const *func, ...)
-{
- int top = lua_gettop(L);
- int nargs = 0;
- int skip = 0;
- int have_error = 0;
- int i = 0;
- char const *arg;
- va_list ap;
- va_start(ap, func);
- while ((arg = va_arg(ap, char const *)) != NULL)
- ++nargs;
- va_end(ap);
- if (nargs > top)
- {
- fputs(MOON_SEP_ "\n", stderr);
- fprintf(stderr, "Lua stack assertion failed:"
- " less stack slots (%d) than expected (%d)!\n",
- top, nargs);
- have_error = 1;
- skip = nargs - top;
- }
- va_start(ap, func);
- for (i = 0; i < skip; ++i)
- arg = va_arg(ap, char const *);
- for (i = top + skip - nargs + 1; i <= top; ++i)
- {
- arg = va_arg(ap, char const *);
- if (!moon_check_type_(L, i, arg))
- {
- if (!have_error)
- fputs(MOON_SEP_ "\n", stderr);
- fprintf(stderr, "Lua stack assertion failed:"
- " '%s' at slot %d (expected %s'%s')!\n",
- moon_type2spec_(lua_type(L, i)), i,
- (arg[0] != '\0' && arg[1] == 0) ? "" : "one of ",
- arg);
- have_error = 1;
- }
- }
- va_end(ap);
- if (have_error)
- {
- moon_stack_(L, file, line, func);
- luaL_error(L, "Lua stack assertion failed!");
- }
-}
-
-MOON_API void moon_stack_(lua_State *L, char const *file, int line,
- char const *func)
-{
- int n = lua_gettop(L);
- int i = 0;
- fputs(MOON_SEP_ "\n", stderr);
- fprintf(stderr, "Lua stack in function '%s' at '%s:%d':\n",
- func != NULL ? func : "(unknown)", file, line);
- for (i = 1; i <= n; ++i)
- {
- fprintf(stderr, "%02d: %s ", i, luaL_typename(L, i));
- switch (lua_type(L, i))
- {
- case LUA_TNONE:
- fputs("(none)\n", stderr);
- break;
- case LUA_TNIL:
- fputs("(nil)\n", stderr);
- break;
- case LUA_TBOOLEAN:
- fprintf(stderr, "(%s)\n", lua_toboolean(L, i) ? "true" : "false");
- break;
- case LUA_TNUMBER:
-#if LUA_VERSION_NUM >= 503
- if (lua_isinteger(L, i))
- fprintf(stderr, "(" LUA_INTEGER_FMT ")\n",
- lua_tointeger(L, i));
- else
-#endif
- fprintf(stderr, "(" LUA_NUMBER_FMT ")\n",
- lua_tonumber(L, i));
- break;
- case LUA_TSTRING:
- {
- char const *str = lua_tostring(L, i);
- char const *ellipsis = "";
-#if LUA_VERSION_NUM < 502
- unsigned len = (unsigned)lua_objlen(L, i);
-#else
- unsigned len = (unsigned)lua_rawlen(L, i);
-#endif
- unsigned i = 0;
- fprintf(stderr, "(len: %u, str: \"", len);
- if (len > 15)
- {
- len = 15;
- ellipsis = "...";
- }
- for (i = 0; i < len; ++i)
- {
- if (isprint((unsigned char)str[i]))
- putc((unsigned char)str[i], stderr);
- else
- fprintf(stderr, "\\x%02X", (unsigned)str[i]);
- }
- fputs(ellipsis, stderr);
- fputs("\")\n", stderr);
- break;
- }
- case LUA_TLIGHTUSERDATA:
- fprintf(stderr, "(%p)\n", lua_touserdata(L, i));
- break;
- case LUA_TUSERDATA:
- if (luaL_getmetafield(L, i, "__name"))
- {
- char const *name = lua_tostring(L, -1);
- fprintf(stderr, "(type: \"%s\", size: %u, ptr: %p)\n",
- name != NULL ? name : "(NULL)",
-#if LUA_VERSION_NUM < 502
- (unsigned)lua_objlen(L, i),
-#else
- (unsigned)lua_rawlen(L, i),
-#endif
- lua_touserdata(L, i));
- lua_pop(L, 1);
- }
- else
- {
- fprintf(stderr, "(size: %u, ptr: %p)\n",
-#if LUA_VERSION_NUM < 502
- (unsigned)lua_objlen(L, i),
-#else
- (unsigned)lua_rawlen(L, i),
-#endif
- lua_touserdata(L, i));
- }
- break;
- default: /* thread, table, function */
- fprintf(stderr, "(%p)\n", lua_topointer(L, i));
- break;
- }
- }
- fputs(MOON_SEP_ "\n", stderr);
-}
-
-#undef MOON_SEP_
-
-/* clean up internally used macros */
-#undef MOON_ALIGNOF_
-#undef MOON_OBJ_ALIGNMENT_
-#undef MOON_PTR_ALIGNMENT_
-#undef MOON_GCF_ALIGNMENT_
-#undef MOON_VCK_ALIGNMENT_
-#undef MOON_ROUNDTO_
-#undef MOON_PTR_
-
-#endif /* MOON_C_ */
diff --git a/framework/3rd/moon/moon.h b/framework/3rd/moon/moon.h
deleted file mode 100644
index 051c358..0000000
--- a/framework/3rd/moon/moon.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/* Copyright 2013-2016 Philipp Janda
- *
- * You may do anything with this work that copyright law would normally
- * restrict, so long as you retain the above notice(s) and this license
- * in all redistributed copies and derived works. There is no warranty.
- */
-
-#ifndef MOON_H_
-#define MOON_H_
-
-/* file: moon.h
- * Utility functions/macros for binding C code to Lua.
- */
-
-#include
-#if defined(__cplusplus) && !defined(MOON_LUA_CPP)
-extern "C"
-{
-#endif
-#include
-#include
-#if defined(__cplusplus) && !defined(MOON_LUA_CPP)
-}
-#define MOON_LLINKAGE_BEGIN \
- extern "C" \
- {
-#define MOON_LLINKAGE_END }
-#endif
-
-/* use default linkage for functions to pass to Lua */
-#ifndef MOON_LLINKAGE_BEGIN
-#define MOON_LLINKAGE_BEGIN
-#define MOON_LLINKAGE_END
-#endif
-
-#define MOON_VERSION (300)
-#define MOON_VERSION_MAJOR (MOON_VERSION / 100)
-#define MOON_VERSION_MINOR (MOON_VERSION - (MOON_VERSION_MAJOR * 100))
-
-/* fake CLANG feature detection on other compilers */
-#ifndef __has_attribute
-#define __has_attribute(x) 0
-#endif
-
-/* platform independent attributes for exporting/importing functions
- * from shared libraries */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#ifndef MOON_LOCAL
-#define MOON_LOCAL
-#endif
-#ifndef MOON_EXPORT
-#define MOON_EXPORT __declspec(dllexport)
-#endif
-#ifndef MOON_IMPORT
-#define MOON_IMPORT __declspec(dllimport)
-#endif
-#elif (defined(__GNUC__) && __GNUC__ >= 4) || __has_attribute(__visibility__)
-#ifndef MOON_LOCAL
-#define MOON_LOCAL __attribute__((__visibility__("hidden")))
-#endif
-#ifndef MOON_EXPORT
-#define MOON_EXPORT __attribute__((__visibility__("default")))
-#endif
-#ifndef MOON_IMPORT
-#define MOON_IMPORT __attribute__((__visibility__("default")))
-#endif
-#endif
-
-#ifndef MOON_LOCAL
-#define MOON_LOCAL
-#endif
-
-#ifndef MOON_EXPORT
-#define MOON_EXPORT
-#endif
-
-#ifndef MOON_IMPORT
-#define MOON_IMPORT
-#endif
-
-/* handle linking tricks for moon toolkit */
-#if defined(MOON_PREFIX)
-/* - change the symbol names of functions to avoid linker conflicts
- * - moon.c needs to be compiled (and linked) separately
- */
-#if !defined(MOON_API)
-/* the following is fine for static linking moon.c to your C module */
-#define MOON_API MOON_LOCAL
-#endif
-#undef MOON_INCLUDE_SOURCE
-#else /* MOON_PREFIX */
-/* - make all functions static and include the source (moon.c)
- * - don't change the symbol names of functions
- * - moon.c doesn't need to be compiled (and linked) separately
- */
-#define MOON_PREFIX moon
-#undef MOON_API
-#if defined(__GNUC__) || __has_attribute(__unused__)
-#define MOON_API __attribute__((__unused__)) static
-#else
-#define MOON_API static
-#endif
-#define MOON_INCLUDE_SOURCE
-#endif /* MOON_PREFIX */
-
-/* some helper macros */
-#define MOON_CONCAT_HELPER(a, b) a##b
-#define MOON_CONCAT(a, b) MOON_CONCAT_HELPER(a, b)
-#define MOON_STRINGIFY_HELPER(a) #a
-#define MOON_STRINGIFY(a) MOON_STRINGIFY_HELPER(a)
-
-/* make sure all functions can be called using the moon_ prefix, even
- * if we change the prefix behind the scenes */
-#define moon_defobject MOON_CONCAT(MOON_PREFIX, _defobject)
-#define moon_newobject MOON_CONCAT(MOON_PREFIX, _newobject)
-#define moon_newpointer MOON_CONCAT(MOON_PREFIX, _newpointer)
-#define moon_newfield MOON_CONCAT(MOON_PREFIX, _newfield)
-#define moon_getmethods MOON_CONCAT(MOON_PREFIX, _getmethods)
-#define moon_killobject MOON_CONCAT(MOON_PREFIX, _killobject)
-#define moon_defcast MOON_CONCAT(MOON_PREFIX, _defcast)
-#define moon_checkobject MOON_CONCAT(MOON_PREFIX, _checkobject)
-#define moon_testobject MOON_CONCAT(MOON_PREFIX, _testobject)
-#define moon_derive MOON_CONCAT(MOON_PREFIX, _derive)
-#define moon_downcast MOON_CONCAT(MOON_PREFIX, _downcast)
-#define moon_checkint MOON_CONCAT(MOON_PREFIX, _checkint)
-#define moon_optint MOON_CONCAT(MOON_PREFIX, _optint)
-#define moon_atexit MOON_CONCAT(MOON_PREFIX, _atexit)
-#define moon_setuvfield MOON_CONCAT(MOON_PREFIX, _setuvfield)
-#define moon_getuvfield MOON_CONCAT(MOON_PREFIX, _getuvfield)
-#define moon_getcache MOON_CONCAT(MOON_PREFIX, _getcache)
-#define moon_stack_ MOON_CONCAT(MOON_PREFIX, _stack_)
-#define moon_stack_assert_ MOON_CONCAT(MOON_PREFIX, _stack_assert_)
-
-/* all objects defined via moon_defobject share a common header of the
- * following type: */
-typedef struct
-{
- unsigned char flags;
- unsigned char cleanup_offset;
- unsigned char vcheck_offset;
- unsigned char object_offset;
-} moon_object_header;
-
-/* flag values in moon_object_header: */
-#define MOON_OBJECT_IS_VALID 0x01u
-#define MOON_OBJECT_IS_POINTER 0x02u
-
-/* function pointer type for "casts" */
-typedef void *(*moon_object_cast)(void *);
-
-/* function pointer type for destructors */
-typedef void (*moon_object_destructor)(void *);
-
-/* additional Lua API functions in this toolkit */
-MOON_API void moon_defobject(lua_State *L, char const *tname,
- size_t sz, luaL_Reg const *methods,
- int nup);
-MOON_API void *moon_newobject(lua_State *L, char const *tname,
- moon_object_destructor destructor);
-MOON_API void **moon_newpointer(lua_State *L, char const *tname,
- moon_object_destructor destructor);
-MOON_API void **moon_newfield(lua_State *L, char const *tname,
- int idx, int (*isvalid)(void *p),
- void *p);
-MOON_API int moon_getmethods(lua_State *L, char const *tname);
-MOON_API void moon_killobject(lua_State *L, int idx);
-MOON_API void moon_defcast(lua_State *L, char const *tname1,
- char const *tname2,
- moon_object_cast cast);
-MOON_API void *moon_checkobject(lua_State *L, int idx,
- char const *tname);
-MOON_API void *moon_testobject(lua_State *L, int idx,
- char const *tname);
-
-MOON_LLINKAGE_BEGIN
-MOON_API int moon_derive(lua_State *L);
-MOON_API int moon_downcast(lua_State *L);
-MOON_LLINKAGE_END
-
-MOON_API lua_Integer moon_checkint(lua_State *L, int idx,
- lua_Integer low,
- lua_Integer high);
-MOON_API lua_Integer moon_optint(lua_State *L, int idx,
- lua_Integer low, lua_Integer high,
- lua_Integer def);
-MOON_API int *moon_atexit(lua_State *L, lua_CFunction func);
-MOON_API int moon_getuvfield(lua_State *L, int i, char const *key);
-MOON_API void moon_setuvfield(lua_State *L, int i, char const *key);
-MOON_API void moon_getcache(lua_State *L, int index);
-MOON_API void moon_stack_(lua_State *L, char const *file, int line,
- char const *func);
-MOON_API void moon_stack_assert_(lua_State *L, char const *file,
- int line, char const *func, ...);
-
-/* some debugging macros */
-#ifndef NDEBUG
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
- defined(__GNUC__) || defined(__clang__)
-#define moon_stack_assert(L, ...) \
- moon_stack_assert_(L, __FILE__, __LINE__, __func__, __VA_ARGS__, (char const *)NULL)
-#define moon_stack(L) \
- moon_stack_(L, __FILE__, __LINE__, __func__)
-#elif defined(_MSC_VER) && _MSC_VER >= 1100L
-#define moon_stack_assert(L, ...) \
- moon_stack_assert_(L, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__, (char const *)NULL)
-#define moon_stack(L) \
- moon_stack_(L, __FILE__, __LINE__, __FUNCTION__)
-#else
-#error preprocessor does not support variadic macros
-#endif
-#else
-#define moon_stack(L) ((void)(0))
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
- (defined(_MSC_VER) && _MSC_VER >= 1100L) || \
- defined(__GNUC__) || defined(__clang__)
-#define moon_stack_assert(...) ((void)0)
-#else
-#error preprocessor does not support variadic macros
-#endif
-#endif
-
-/* Lua version compatibility is out of scope for this library, so only
- * compatibility functions needed for the implementation are provided.
- * Consider using the Compat-5.3 project which provides backports of
- * many Lua 5.3 C API functions for Lua 5.1 and 5.2.
- */
-#if LUA_VERSION_NUM < 502
-MOON_API int moon_absindex(lua_State *L, int idx);
-#else
-#define moon_absindex(L, i) lua_absindex((L), (i))
-#endif
-
-#if defined(MOON_INCLUDE_SOURCE)
-#include "moon.c"
-#endif
-
-#endif /* MOON_H_ */
diff --git a/framework/3rd/moon/moon_dlfix.h b/framework/3rd/moon/moon_dlfix.h
deleted file mode 100644
index 0158336..0000000
--- a/framework/3rd/moon/moon_dlfix.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* Copyright 2013-2016 Philipp Janda
- *
- * You may do anything with this work that copyright law would normally
- * restrict, so long as you retain the above notice(s) and this license
- * in all redistributed copies and derived works. There is no warranty.
- */
-
-#ifndef MOON_DLFIX_H_
-#define MOON_DLFIX_H_
-
-/* Provides a C function macro that tries to reopen the Lua library
- * in global mode, so that C extension modules do not have to be
- * relinked for Lua VMs in shared libraries.
- */
-
-/* enable/disable debug output */
-#if 0
-#include
-#define MOON_DLFIX_DBG(_a) (printf _a)
-#else
-#define MOON_DLFIX_DBG(_a) ((void)0)
-#endif
-
-/* detect some form of UNIX, so that unistd.h can be included to
- * use other feature macros */
-#if defined(unix) || defined(__unix) || defined(__unix__) || \
- defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \
- (defined(__APPLE__) && defined(__MACH__)) || \
- defined(HAVE_UNISTD_H)
-
-#include
-/* check for minimum POSIX version that specifies dlopen etc. */
-#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || \
- defined(HAVE_DLFCN_H)
-
-#include
-/* check for the existence of the RTLD_NOLOAD flag
- * - GLIBC has it (since 2.2)
- * - FreeBSD has it
- * - ...
- */
-#ifdef RTLD_NOLOAD
-
-/* Lua VM library names to try
- * Most of them require the dev-package to be installed,
- * but guessing the real library names for multiple distros
- * is pretty difficult ...
- * If the library is not in the default search path you can
- * set LD_LIBRARY_PATH, or use MOON_DLFIX_LIBNAME to specify
- * an absolute path to the library.
- */
-static char const *const moon_dlfix_lib_names[] = {
-/* you can define your own custom name via compiler define: */
-#ifdef MOON_DLFIX_LIBNAME
- MOON_DLFIX_LIBNAME,
-#endif /* custom Lua library name */
- "liblua5.4.so", /* Lua 5.4, Debian/Ubuntu naming */
- "liblua5.4.so.0", /* same with common SONAME */
- "liblua54.so",
- "liblua5.3.so", /* Lua 5.3, Debian/Ubuntu naming */
- "liblua5.3.so.0", /* same with common SONAME */
- "liblua53.so",
- "liblua5.2.so", /* Lua 5.2, Debian/Ubuntu naming */
- "liblua5.2.so.0", /* same with common SONAME */
- "liblua52.so",
- "liblua.so", /* default name from Lua's makefile */
- "liblua5.1.so", /* Lua 5.1, Debian/Ubuntu naming */
- "liblua5.1.so.0", /* same with common SONAME */
- "liblua51.so",
- "libluajit-5.1.so", /* LuaJIT default name */
- "libluajit-5.1.so.2", /* common SONAME */
-};
-
-/* On some OSes we can iterate over all loaded libraries to
- * find the Lua shared object.
- */
-#if defined(__linux__) && defined(_GNU_SOURCE)
-#define MOON_DLFIX_DL_ITERATE_PHDR
-#include
-#endif /* Linux with dl_iterate_phdr() function */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || \
- defined(__NetBSD__) || defined(__OpenBSD__)
-#define MOON_DLFIX_DL_ITERATE_PHDR
-#include
-#endif /* BSDs with dl_iterate_phdr() function */
-
-#if !defined(MOON_DLFIX_FIND) && \
- defined(MOON_DLFIX_DL_ITERATE_PHDR)
-#include
-
-#ifndef MOON_DLFIX_LIBPREFIX
-#define MOON_DLFIX_LIBPREFIX "liblua"
-#endif
-
-static int moon_dlfix_cb(struct dl_phdr_info *info, size_t size,
- void *data)
-{
- int *found = data;
- void *dl = dlopen(info->dlpi_name, RTLD_LAZY);
- (void)size;
- MOON_DLFIX_DBG(("Checking ELF object '%s'.\n", info->dlpi_name));
- if (dl)
- {
- if (dlsym(dl, "lua_gettop"))
- {
- MOON_DLFIX_DBG(("'%s' does have Lua symbols.\n", info->dlpi_name));
- /* the Lua API could be in a dependency, so test the library
- * name for "liblua" */
- char const *libname = strrchr(info->dlpi_name, '/');
- if (libname)
- ++libname; /* skip slash */
- else
- libname = info->dlpi_name;
- if (0 == strncmp(libname, MOON_DLFIX_LIBPREFIX,
- sizeof(MOON_DLFIX_LIBPREFIX) - 1))
- {
- void *dl2 = dlopen(info->dlpi_name,
- RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
- if (dl2)
- {
- MOON_DLFIX_DBG(("Found and fixed Lua SO!\n"));
- dlclose(dl2);
- *found = 1;
- }
- }
- }
- dlclose(dl);
- }
- return *found;
-}
-
-static int moon_dlfix_find(void)
-{
- int found = 0;
- MOON_DLFIX_DBG(("Iterating all loaded ELF objects ...\n"));
- return dl_iterate_phdr(moon_dlfix_cb, &found);
-}
-#define MOON_DLFIX_FIND() (moon_dlfix_find())
-#endif /* has dl_iterate_phdr() function */
-
-#if !defined(MOON_DLFIX_FIND)
-/* dummy definition (always returns failure) */
-#define MOON_DLFIX_FIND() (0)
-#endif
-
-/* Try to iterate all loaded shared libraries using a platform-
- * specific way to find a loaded Lua shared library.
- * If that fails, try a list of common library names.
- * In all cases reopen the Lua library using RTLD_GLOBAL and
- * RTLD_NOLOAD.
- */
-#define MOON_DLFIX() \
- do \
- { \
- if (!MOON_DLFIX_FIND()) \
- { \
- unsigned i = 0; \
- MOON_DLFIX_DBG(("Trying some common Lua library names ...\n")); \
- for (; i < sizeof(moon_dlfix_lib_names) / sizeof(*moon_dlfix_lib_names); ++i) \
- { \
- void *dl = dlopen(moon_dlfix_lib_names[i], RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD); \
- MOON_DLFIX_DBG(("Trying '%s'.\n", moon_dlfix_lib_names[i])); \
- if (dl) \
- { \
- MOON_DLFIX_DBG(("Fixed Lua SO.\n")); \
- dlclose(dl); \
- break; \
- } \
- } \
- } \
- } while (0)
-
-#endif /* has RTLD_NOLOAD */
-#endif /* has dlfcn.h */
-#endif /* has unistd.h */
-
-/* define fallback */
-#ifndef MOON_DLFIX
-#define MOON_DLFIX() \
- (MOON_DLFIX_DBG(("moon_dlfix functionality not available!\n")))
-#endif
-
-#endif /* MOON_DLFIX_H_ */
diff --git a/framework/3rd/moon/moon_flag.h b/framework/3rd/moon/moon_flag.h
deleted file mode 100644
index 664484e..0000000
--- a/framework/3rd/moon/moon_flag.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Copyright 2013-2015 Philipp Janda
- *
- * You may do anything with this work that copyright law would normally
- * restrict, so long as you retain the above notice(s) and this license
- * in all redistributed copies and derived works. There is no warranty.
- */
-
-/* this include file is a macro file which could be included
- * multiple times with different settings.
- */
-#include "moon.h"
-
-/* "parameter checking" */
-#ifndef MOON_FLAG_NAME
-#error MOON_FLAG_NAME is not defined
-#endif
-
-#ifndef MOON_FLAG_TYPE
-#error MOON_FLAG_TYPE is not defined
-#endif
-
-#ifndef MOON_FLAG_SUFFIX
-#error MOON_FLAG_SUFFIX is not defined
-#endif
-
-#define MOON_FLAG_ADD MOON_CONCAT(moon_flag_add_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_SUB MOON_CONCAT(moon_flag_sub_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_CALL MOON_CONCAT(moon_flag_call_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_AND MOON_CONCAT(moon_flag_and_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_NOT MOON_CONCAT(moon_flag_not_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_EQ MOON_CONCAT(moon_flag_eq_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_DEF MOON_CONCAT(moon_flag_def_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_NEW MOON_CONCAT(moon_flag_new_, MOON_FLAG_SUFFIX)
-#define MOON_FLAG_GET MOON_CONCAT(moon_flag_get_, MOON_FLAG_SUFFIX)
-#ifndef MOON_FLAG_EQMETHOD
-#define MOON_FLAG_EQMETHOD(a, b) ((a) == (b))
-#endif
-
-static void MOON_FLAG_NEW(lua_State *L, MOON_FLAG_TYPE v)
-{
-#ifdef MOON_FLAG_USECACHE
- luaL_checkstack(L, 5, MOON_STRINGIFY(MOON_FLAG_NEW));
- luaL_getmetatable(L, MOON_FLAG_NAME);
- if (!lua_istable(L, -1))
- luaL_error(L, "no metatable for type '%s' defined", MOON_FLAG_NAME);
- moon_getcache(L, -1);
- lua_pushnumber(L, (lua_Number)v);
- lua_rawget(L, -2);
- if (lua_isnil(L, -1))
- {
- lua_pop(L, 1);
-#endif
- *(MOON_FLAG_TYPE *)moon_newobject(L, MOON_FLAG_NAME, 0) = v;
-#ifdef MOON_FLAG_USECACHE
- lua_pushnumber(L, (lua_Number)v);
- lua_pushvalue(L, -2);
- lua_rawset(L, -4);
- }
- lua_replace(L, -3);
- lua_pop(L, 1);
-#endif
-}
-
-static MOON_FLAG_TYPE MOON_FLAG_GET(lua_State *L, int index)
-{
- return *(MOON_FLAG_TYPE *)moon_checkobject(L, index, MOON_FLAG_NAME);
-}
-
-#ifndef MOON_FLAG_NOBITOPS
-MOON_LLINKAGE_BEGIN
-static int MOON_FLAG_ADD(lua_State *L)
-{
- MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
- MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
- MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(*a | *b));
- return 1;
-}
-static int MOON_FLAG_SUB(lua_State *L)
-{
- MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
- MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
- MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(*a & ~(*b)));
- return 1;
-}
-static int MOON_FLAG_CALL(lua_State *L)
-{
- MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
- MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
- lua_pushboolean(L, !(~(*a) & (*b)));
- return 1;
-}
-#if LUA_VERSION_NUM > 502
-static int MOON_FLAG_AND(lua_State *L)
-{
- MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
- MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
- MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(*a & *b));
- return 1;
-}
-static int MOON_FLAG_NOT(lua_State *L)
-{
- MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
- MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(~*a));
- return 1;
-}
-#endif
-MOON_LLINKAGE_END
-#endif
-
-#ifndef MOON_FLAG_NORELOPS
-MOON_LLINKAGE_BEGIN
-static int MOON_FLAG_EQ(lua_State *L)
-{
- MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
- MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
- lua_pushboolean(L, MOON_FLAG_EQMETHOD(*a, *b));
- return 1;
-}
-MOON_LLINKAGE_END
-#endif
-
-static void MOON_FLAG_DEF(lua_State *L)
-{
- luaL_Reg const methods[] = {
-#ifndef MOON_FLAG_NOBITOPS
- {"__add", MOON_FLAG_ADD},
- {"__sub", MOON_FLAG_SUB},
- {"__call", MOON_FLAG_CALL},
-#if LUA_VERSION_NUM > 502
- {"__band", MOON_FLAG_AND},
- {"__bor", MOON_FLAG_ADD},
- {"__bnot", MOON_FLAG_NOT},
-#endif
-#endif
-#ifndef MOON_FLAG_NORELOPS
- {"__eq", MOON_FLAG_EQ},
-#endif
- {NULL, NULL}
- };
- moon_defobject(L, MOON_FLAG_NAME, sizeof(MOON_FLAG_TYPE),
- methods, 0);
-}
-
-#undef MOON_FLAG_ADD
-#undef MOON_FLAG_SUB
-#undef MOON_FLAG_CALL
-#undef MOON_FLAG_AND
-#undef MOON_FLAG_NOT
-#undef MOON_FLAG_EQ
-#undef MOON_FLAG_NEW
-#undef MOON_FLAG_DEF
-#undef MOON_FLAG_GET
-
-#undef MOON_FLAG_NAME
-#undef MOON_FLAG_TYPE
-#undef MOON_FLAG_SUFFIX
-#undef MOON_FLAG_NOBITOPS
-#undef MOON_FLAG_NORELOPS
-#undef MOON_FLAG_USECACHE
-#undef MOON_FLAG_EQMETHOD
diff --git a/framework/lualib-src/lua-math3d/README.md b/framework/lualib-src/lua-math3d/README.md
deleted file mode 100644
index 39aeb04..0000000
--- a/framework/lualib-src/lua-math3d/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## 用途
-
-现在3d游戏开发已经很普遍,如果服务端涉及到3d数学方面的计算就需要一个开源的3d数学库,网上开源的3d数学库大部分都是右手坐标。而我们所使用的客户端大部分都是unity,众所周知unity是左手坐标系的数学库。所以一个基于左手坐标系的3d数学库就很有必要。本库是基于云风的项目[ejoy3d](https://github.com/cloudwu/ejoy3d)所修改。包含左手库和右手库,如要切换可直接在libmath.c的首行进行修改。
-
-本项目是基于lua的动态库,如果不需要使用lua,可直接使用math3d-left.h和math3d-right.h
diff --git a/framework/lualib-src/lua-math3d/lua-math3d.c b/framework/lualib-src/lua-math3d/lua-math3d.c
deleted file mode 100644
index 8d3a792..0000000
--- a/framework/lualib-src/lua-math3d/lua-math3d.c
+++ /dev/null
@@ -1,853 +0,0 @@
-#include "math3d-left.h"
-#include
-#include
-
-// https://github.com/huanzai/math3d
-
-static void *
-check_userdata(lua_State *L, int idx)
-{
- void *ret = lua_touserdata(L, idx);
- luaL_argcheck(L, ret != NULL, idx, "Userdata should not be NULL");
- return ret;
-}
-
-static int
-lnewvec3(lua_State *L)
-{
- struct vector3 tmp;
- if (lua_isuserdata(L, 1))
- {
- struct vector3 *copy = check_userdata(L, 1);
- tmp = *copy;
- }
- else
- {
- tmp.x = luaL_optnumber(L, 1, 0);
- tmp.y = luaL_optnumber(L, 2, 0);
- tmp.z = luaL_optnumber(L, 3, 0);
- }
- struct vector3 *vec3 = lua_newuserdata(L, sizeof(*vec3));
- *vec3 = tmp;
- lua_pushvalue(L, lua_upvalueindex(1));
- lua_setmetatable(L, -2);
- return 1;
-}
-
-static int
-lvec3_pack(lua_State *L)
-{
- struct vector3 *vec3 = check_userdata(L, 1);
- vec3->x = luaL_optnumber(L, 2, 0);
- vec3->y = luaL_optnumber(L, 3, 0);
- vec3->z = luaL_optnumber(L, 4, 0);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_unpack(lua_State *L)
-{
- struct vector3 *vec3 = check_userdata(L, 1);
- lua_pushnumber(L, vec3->x);
- lua_pushnumber(L, vec3->y);
- lua_pushnumber(L, vec3->z);
- return 3;
-}
-
-static int
-lvec3_dot(lua_State *L)
-{
- struct vector3 *a = check_userdata(L, 1);
- struct vector3 *b = check_userdata(L, 2);
- float v = vector3_dot(a, b);
- lua_pushnumber(L, v);
- return 1;
-}
-
-static int
-lvec3_cross(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct vector3 *a = check_userdata(L, 2);
- struct vector3 *b = check_userdata(L, 3);
- vector3_cross(v, a, b);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_vector(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct vector3 *a = check_userdata(L, 2);
- struct vector3 *b = check_userdata(L, 3);
- vector3_vector(v, a, b);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_length(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- float len = vector3_length(v);
- lua_pushnumber(L, len);
- return 1;
-}
-
-static int
-lvec3_normalize(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- vector3_normalize(v);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_copy(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct vector3 *from = check_userdata(L, 2);
- *v = *from;
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_tostring(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- lua_pushfstring(L, "[%f, %f, %f]", v->x, v->y, v->z);
-
- return 1;
-}
-
-static int
-lvec3_rotation(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct vector3 *from = check_userdata(L, 2);
- vector3_to_rotation(v, from);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_lerp(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct vector3 *a = check_userdata(L, 2);
- struct vector3 *b = check_userdata(L, 3);
- float f = luaL_checknumber(L, 4);
- vector3_lerp(v, a, b, f);
- lua_settop(L, 1);
- return 1;
-}
-
-static void
-create_meta(lua_State *L, luaL_Reg *l, const char *name, lua_CFunction tostring)
-{
- int n = 0;
- while (l[n].name)
- ++n;
- lua_newtable(L);
- lua_createtable(L, 0, n);
- int i;
- for (i = 0; i < n; i++)
- {
- lua_pushcfunction(L, l[i].func);
- lua_setfield(L, -2, l[i].name);
- }
- lua_setfield(L, -2, "__index");
- lua_pushstring(L, name);
- lua_setfield(L, -2, "__metatable");
- lua_pushcfunction(L, tostring);
- lua_setfield(L, -2, "__tostring");
-}
-
-static int
-lvec3_transmat(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- matrix44_trans(m, v->x, v->y, v->z);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lvec3_scalemat(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- matrix44_scale(m, v->x, v->y, v->z);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lvec3_rotmat(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- matrix44_rot(m, v->x, v->y, v->z);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lvec3_rotaxis(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- float angle = luaL_checknumber(L, 3);
- matrix44_rot_axis(m, v, angle);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lvec3_mul(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- vector3_mul(v, m);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_mul33(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- vector3_mul33(v, m);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lvec3_distAABB(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct vector3 *mins = check_userdata(L, 2);
- struct vector3 *maxs = check_userdata(L, 3);
- float d = vector3_distAABB(v, mins, maxs);
- lua_pushnumber(L, d);
- return 1;
-}
-
-static int
-lvec3_plane(lua_State *L)
-{
- struct vector3 *v = check_userdata(L, 1);
- struct plane *p = check_userdata(L, 2);
- float d = luaL_optnumber(L, 3, 0);
- plane_init(p, v, d);
- lua_settop(L, 2);
- return 1;
-}
-
-static void
-vector3(lua_State *L)
-{
- luaL_Reg l[] = {
- {"pack", lvec3_pack},
- {"unpack", lvec3_unpack},
- {"dot", lvec3_dot},
- {"cross", lvec3_cross},
- {"vector", lvec3_vector},
- {"length", lvec3_length},
- {"normalize", lvec3_normalize},
- {"copy", lvec3_copy},
- {"rotation", lvec3_rotation},
- {"lerp", lvec3_lerp},
- {"transmat", lvec3_transmat},
- {"scalemat", lvec3_scalemat},
- {"rotmat", lvec3_rotmat},
- {"rotaxis", lvec3_rotaxis},
- {"mul", lvec3_mul},
- {"mul33", lvec3_mul33},
- {"plane", lvec3_plane},
- {"distAABB", lvec3_distAABB},
- {NULL, NULL},
- };
- create_meta(L, l, "vector3", lvec3_tostring);
- lua_pushcclosure(L, lnewvec3, 1);
-}
-
-static int
-lnewquat(lua_State *L)
-{
- if (lua_isuserdata(L, 1))
- {
- struct quaternion *tmp = check_userdata(L, 1);
- struct quaternion *q = lua_newuserdata(L, sizeof(*q));
- *q = *tmp;
- }
- else if lua_isnoneornil (L, 1)
- {
- struct quaternion *q = lua_newuserdata(L, sizeof(*q));
- q->x = 0;
- q->y = 0;
- q->z = 0;
- q->w = 1.0f;
- }
- else
- {
- float x = luaL_checknumber(L, 1);
- float y = luaL_checknumber(L, 2);
- float z = luaL_checknumber(L, 3);
- struct quaternion *q = lua_newuserdata(L, sizeof(*q));
- quaternion_init(q, x, y, z);
- }
- lua_pushvalue(L, lua_upvalueindex(1));
- lua_setmetatable(L, -2);
-
- return 1;
-}
-
-static int
-lquat_tostring(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- lua_pushfstring(L, "[%f, %f, %f, %f]", q->x, q->y, q->z, q->w);
-
- return 1;
-}
-
-static int
-lquat_mul(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- struct quaternion *a = check_userdata(L, 2);
- struct quaternion *b = check_userdata(L, 3);
- quaternion_mul(q, a, b);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lquat_copy(lua_State *L)
-{
- struct quaternion *a = check_userdata(L, 1);
- struct quaternion *b = check_userdata(L, 2);
- *a = *b;
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lquat_slerp(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- struct quaternion *a = check_userdata(L, 2);
- struct quaternion *b = check_userdata(L, 3);
- float t = luaL_checknumber(L, 4);
- quaternion_slerp(q, a, b, t);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lquat_nslerp(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- struct quaternion *a = check_userdata(L, 2);
- struct quaternion *b = check_userdata(L, 3);
- float t = luaL_checknumber(L, 4);
- quaternion_nslerp(q, a, b, t);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lquat_inverted(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- quaternion_inverted(q);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lquat_matrix(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- union matrix44 *mat = check_userdata(L, 2);
- matrix44_from_quaternion(mat, q);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lquat_pack(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- q->x = luaL_checknumber(L, 2);
- q->y = luaL_checknumber(L, 3);
- q->z = luaL_checknumber(L, 4);
- q->w = luaL_checknumber(L, 5);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lquat_unpack(lua_State *L)
-{
- struct quaternion *q = check_userdata(L, 1);
- lua_pushnumber(L, q->x);
- lua_pushnumber(L, q->y);
- lua_pushnumber(L, q->z);
- lua_pushnumber(L, q->w);
- return 4;
-}
-
-static void
-quaternion(lua_State *L)
-{
- luaL_Reg l[] = {
- {"mul", lquat_mul},
- {"copy", lquat_copy},
- {"pack", lquat_pack},
- {"unpack", lquat_unpack},
- {"slerp", lquat_slerp},
- {"nslerp", lquat_nslerp},
- {"inverted", lquat_inverted},
- {"matrix", lquat_matrix},
- {NULL, NULL},
- };
- create_meta(L, l, "quateraion", lquat_tostring);
- lua_pushcclosure(L, lnewquat, 1);
-}
-
-static int
-lnewmat(lua_State *L)
-{
- if (lua_isuserdata(L, 1))
- {
- union matrix44 *tmp = check_userdata(L, 1);
- union matrix44 *mat = lua_newuserdata(L, sizeof(*mat));
- *mat = *tmp;
- }
- else if lua_isnoneornil (L, 1)
- {
- union matrix44 *mat = lua_newuserdata(L, sizeof(*mat));
- matrix44_identity(mat);
- }
- else
- {
- float x = luaL_checknumber(L, 1);
- float y = luaL_checknumber(L, 2);
- float z = luaL_checknumber(L, 3);
- union matrix44 *mat = lua_newuserdata(L, sizeof(*mat));
- matrix44_rot(mat, x, y, z);
- }
- lua_pushvalue(L, lua_upvalueindex(1));
- lua_setmetatable(L, -2);
-
- return 1;
-}
-
-static int
-lmat_tostring(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- lua_pushfstring(L, "[(%f, %f, %f, %f) (%f, %f, %f, %f) (%f, %f, %f, %f) (%f, %f, %f, %f)]",
- m->c[0][0], m->c[0][1], m->c[0][2], m->c[0][3],
- m->c[1][0], m->c[1][1], m->c[1][2], m->c[1][3],
- m->c[2][0], m->c[2][1], m->c[2][2], m->c[2][3],
- m->c[3][0], m->c[3][1], m->c[3][2], m->c[3][3]);
- return 1;
-}
-
-static int
-lmat_pack(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- int i;
- for (i = 0; i < 16; i++)
- {
- m->x[i] = luaL_checknumber(L, 2 + i);
- }
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_unpack(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- int i;
- for (i = 0; i < 16; i++)
- {
- lua_pushnumber(L, m->x[i]);
- }
- return 16;
-}
-
-static int
-lmat_copy(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- union matrix44 *from = check_userdata(L, 2);
- *m = *from;
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_identity(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- matrix44_identity(m);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_perspective(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- float l = luaL_checknumber(L, 2);
- float r = luaL_checknumber(L, 3);
- float b = luaL_checknumber(L, 4);
- float t = luaL_checknumber(L, 5);
- float n = luaL_checknumber(L, 6);
- float f = luaL_checknumber(L, 7);
- matrix44_perspective(m, l, r, b, t, n, f);
-
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_ortho(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- float l = luaL_checknumber(L, 2);
- float r = luaL_checknumber(L, 3);
- float b = luaL_checknumber(L, 4);
- float t = luaL_checknumber(L, 5);
- float n = luaL_checknumber(L, 6);
- float f = luaL_checknumber(L, 7);
- matrix44_ortho(m, l, r, b, t, n, f);
-
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_mul(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- union matrix44 *a = check_userdata(L, 2);
- union matrix44 *b = check_userdata(L, 3);
- if (b == NULL)
- {
- b = a;
- a = m;
- }
- matrix44_mul(m, a, b);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_fastmul43(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- union matrix44 *a = check_userdata(L, 2);
- union matrix44 *b = check_userdata(L, 3);
- matrix44_fastmul43(m, a, b);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_transposed(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- matrix44_transposed(m);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_determinant(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- float v = matrix44_determinant(m);
- lua_pushnumber(L, v);
- return 1;
-}
-
-static int
-lmat_inverted(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- union matrix44 *from = check_userdata(L, 2);
- matrix44_inverted(m, from);
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lmat_trans(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- struct vector3 *v = check_userdata(L, 2);
- matrix44_gettrans(m, v);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lmat_scale(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- struct vector3 *v = check_userdata(L, 2);
- matrix44_getscale(m, v);
- lua_settop(L, 2);
- return 1;
-}
-
-static int
-lmat_decompose(lua_State *L)
-{
- union matrix44 *m = check_userdata(L, 1);
- struct vector3 *trans = check_userdata(L, 2);
- struct vector3 *rot = check_userdata(L, 3);
- struct vector3 *scale = check_userdata(L, 4);
- matrix44_decompose(m, trans, rot, scale);
- lua_settop(L, 4);
- return 3;
-}
-
-static void
-matrix(lua_State *L)
-{
- luaL_Reg l[] = {
- {"pack", lmat_pack},
- {"unpack", lmat_unpack},
- {"copy", lmat_copy},
- {"identity", lmat_identity},
- {"perspective", lmat_perspective},
- {"ortho", lmat_ortho},
- {"mul", lmat_mul},
- {"fastmul43", lmat_fastmul43},
- {"transposed", lmat_transposed},
- {"determinant", lmat_determinant},
- {"inverted", lmat_inverted},
- {"trans", lmat_trans},
- {"scale", lmat_scale},
- {"decompose", lmat_decompose},
- {NULL, NULL},
- };
- create_meta(L, l, "matrix", lmat_tostring);
- lua_pushcclosure(L, lnewmat, 1);
-}
-
-static int
-lnewvec4(lua_State *L)
-{
- struct vector4 tmp;
- if (lua_isuserdata(L, 1))
- {
- struct vector4 *copy = check_userdata(L, 1);
- tmp = *copy;
- }
- else
- {
- tmp.x = luaL_optnumber(L, 1, 0);
- tmp.y = luaL_optnumber(L, 2, 0);
- tmp.z = luaL_optnumber(L, 3, 0);
- tmp.z = luaL_optnumber(L, 4, 1.0);
- }
- struct vector4 *vec4 = lua_newuserdata(L, sizeof(*vec4));
- *vec4 = tmp;
- lua_pushvalue(L, lua_upvalueindex(1));
- lua_setmetatable(L, -2);
- return 1;
-}
-
-#define lvec4_tostring lquat_tostring
-#define lvec4_copy lquat_copy
-#define lvec4_pack lquat_pack
-#define lvec4_unpack lquat_unpack
-
-static int
-lvec4_mul(lua_State *L)
-{
- struct vector4 *v = check_userdata(L, 1);
- union matrix44 *m = check_userdata(L, 2);
- vector4_mul(v, m);
- lua_settop(L, 1);
- return 1;
-}
-
-static void
-vector4(lua_State *L)
-{
- luaL_Reg l[] = {
- {"copy", lvec4_copy},
- {"pack", lvec4_pack},
- {"unpack", lvec4_unpack},
- {"mul", lvec4_mul},
- {NULL, NULL},
- };
- create_meta(L, l, "vector4", lvec4_tostring);
- lua_pushcclosure(L, lnewvec4, 1);
-}
-
-static int
-lnewplane(lua_State *L)
-{
- int top = lua_gettop(L);
- if (top == 0)
- {
- struct plane *p = lua_newuserdata(L, sizeof(*p));
- p->normal.x = 0;
- p->normal.y = 0;
- p->normal.z = 1;
- p->dist = 0; // XY plane
- }
- else if (top == 1)
- {
- struct plane *copy = check_userdata(L, 1);
- struct plane *p = lua_newuserdata(L, sizeof(*p));
- *p = *copy;
- }
- else if (top == 3)
- {
- struct vector3 *a = check_userdata(L, 1);
- struct vector3 *b = check_userdata(L, 2);
- struct vector3 *c = check_userdata(L, 3);
- struct plane *p = lua_newuserdata(L, sizeof(*p));
- plane_init_dot3(p, a, b, c);
- }
- else
- {
- return luaL_error(L, "Invalid new plane");
- }
- lua_pushvalue(L, lua_upvalueindex(1));
- lua_setmetatable(L, -2);
- return 1;
-}
-
-static int
-lplane_tostring(lua_State *L)
-{
- struct plane *p = check_userdata(L, 1);
- lua_pushfstring(L, "[%f, %f, %f : %f]", p->normal.x, p->normal.x, p->normal.z, p->dist);
- return 1;
-}
-
-static int
-lplane_dist(lua_State *L)
-{
- struct plane *p = check_userdata(L, 1);
- struct vector3 *v = check_userdata(L, 2);
- float d = plane_dist(p, v);
- lua_pushnumber(L, d);
- return 1;
-}
-
-static int
-lplane_copy(lua_State *L)
-{
- struct plane *p = check_userdata(L, 1);
- struct plane *from = check_userdata(L, 2);
- *p = *from;
- lua_settop(L, 1);
- return 1;
-}
-
-static int
-lplane_dot3(lua_State *L)
-{
- struct plane *p = check_userdata(L, 1);
- struct vector3 *a = check_userdata(L, 2);
- struct vector3 *b = check_userdata(L, 3);
- struct vector3 *c = check_userdata(L, 4);
- plane_init_dot3(p, a, b, c);
- lua_settop(L, 1);
- return 1;
-}
-
-static void
-plane(lua_State *L)
-{
- luaL_Reg l[] = {
- {"copy", lplane_copy},
- {"dist", lplane_dist},
- {"dot3", lplane_dot3},
- {NULL, NULL},
- };
- create_meta(L, l, "plane", lplane_tostring);
- lua_pushcclosure(L, lnewplane, 1);
-}
-
-static int
-lraytriangle(lua_State *L)
-{
- int top = lua_gettop(L);
- if (top != 6)
- {
- return luaL_error(L, "intersection.raytriangle(rayOrig,rayDir,p0,p1,p2,ret)");
- }
- struct vector3 *ro = check_userdata(L, 1);
- struct vector3 *rd = check_userdata(L, 2);
- struct vector3 *p0 = check_userdata(L, 3);
- struct vector3 *p1 = check_userdata(L, 4);
- struct vector3 *p2 = check_userdata(L, 5);
- struct vector3 *inst = check_userdata(L, 6);
- if (intersection_raytriangle(ro, rd, p0, p1, p2, inst) == NULL)
- {
- return 0;
- }
- return 1;
-}
-
-static int
-lrayAABB(lua_State *L)
-{
- int top = lua_gettop(L);
- if (top != 4)
- {
- return luaL_error(L, "intersection.rayAABB(rayOrig,rayDir,mins,maxs)");
- }
- struct vector3 *ro = check_userdata(L, 1);
- struct vector3 *rd = check_userdata(L, 2);
- struct vector3 *mins = check_userdata(L, 3);
- struct vector3 *maxs = check_userdata(L, 4);
- int r = intersection_rayAABB(ro, rd, mins, maxs);
- lua_pushboolean(L, r);
- return 1;
-}
-
-int luaopen_math3d(lua_State *L)
-{
- luaL_checkversion(L);
- lua_newtable(L);
- vector3(L);
- lua_setfield(L, -2, "vector3");
- quaternion(L);
- lua_setfield(L, -2, "quaternion");
- matrix(L);
- lua_setfield(L, -2, "matrix");
- vector4(L);
- lua_setfield(L, -2, "vector4");
- plane(L);
- lua_setfield(L, -2, "plane");
- luaL_Reg l[] = {
- {"raytriangle", lraytriangle},
- {"rayAABB", lrayAABB},
- {NULL, NULL},
- };
- luaL_newlib(L, l);
- lua_setfield(L, -2, "intersection");
- return 1;
-}
diff --git a/framework/lualib-src/lua-math3d/math3d-left.h b/framework/lualib-src/lua-math3d/math3d-left.h
deleted file mode 100644
index f75c7c8..0000000
--- a/framework/lualib-src/lua-math3d/math3d-left.h
+++ /dev/null
@@ -1,836 +0,0 @@
-// This is a rewrite version (in C) from Horde3D (utMath.h) , http://www.horde3d.org
-// Math library
-//
-// Coordinate system is left-handed with positive y as up axis
-//
-
-#ifndef ejoy3d_math_h
-#define ejoy3d_math_h
-
-#include
-#include
-#include
-
-struct vector3
-{
- float x, y, z;
-};
-
-struct vector4
-{
- float x, y, z, w;
-};
-
-struct quaternion
-{
- float x, y, z, w;
-};
-
-union matrix44
-{
- float c[4][4];
- float x[16];
-};
-
-struct plane
-{
- struct vector3 normal;
- float dist;
-};
-
-// vector
-
-static inline float *
-vector3_array(struct vector3 *v)
-{
- return (float *)v;
-}
-
-static inline float *
-vector4_array(struct vector4 *v)
-{
- return (float *)v;
-}
-
-static inline float
-vector3_dot(const struct vector3 *a, const struct vector3 *b)
-{
- return a->x * b->x + a->y * b->y + a->z * b->z;
-}
-
-static inline struct vector3 *
-vector3_cross(struct vector3 *v, const struct vector3 *a, const struct vector3 *b)
-{
- float x = a->y * b->z - a->z * b->y;
- float y = a->z * b->x - a->x * b->z;
- float z = a->x * b->y - a->y * b->x;
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-static inline struct vector3 *
-vector3_vector(struct vector3 *v, const struct vector3 *p1, const struct vector3 *p2)
-{
- v->x = p1->x - p2->x;
- v->y = p1->y - p2->y;
- v->z = p1->z - p2->z;
-
- return v;
-}
-
-static inline float
-vector3_length(const struct vector3 *v)
-{
- return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
-}
-
-static inline struct vector3 *
-vector3_normalize(struct vector3 *v)
-{
- float invLen = 1.0f / vector3_length(v);
- v->x *= invLen;
- v->y *= invLen;
- v->z *= invLen;
-
- return v;
-}
-
-static inline struct vector3 *
-vector3_to_rotation(struct vector3 *v, const struct vector3 *r)
-{
- // Assumes that the unrotated view vector is (0, 0, -1)
- v->x = v->y = v->z = 0;
- if (r->y != 0)
- {
- v->x = atan2f(r->y, sqrtf(r->x * r->x + r->z * r->z));
- }
- if (r->x != 0 || r->z != 0)
- {
- v->y = atan2f(-r->x, -r->z);
- }
-
- return v;
-}
-
-static inline struct vector3 *
-vector3_lerp(struct vector3 *v, const struct vector3 *a, const struct vector3 *b, float f)
-{
- float x = a->x + (b->x - a->x) * f;
- float y = a->y + (b->y - a->y) * f;
- float z = a->z + (b->z - a->z) * f;
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-// quaternion
-
-static inline struct quaternion *
-quaternion_mul(struct quaternion *q, const struct quaternion *a, const struct quaternion *b)
-{
- float x = a->y * b->z - a->z * b->y + b->x * a->w + a->x * b->w;
- float y = a->z * b->x - a->x * b->z + b->y * a->w + a->y * b->w;
- float z = a->x * b->y - a->y * b->x + b->z * a->w + a->z * b->w;
- float w = a->w * b->w - (a->x * b->x + a->y * b->y + a->z * b->z);
-
- q->x = x;
- q->y = y;
- q->z = z;
- q->w = w;
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_init(struct quaternion *q, float x, float y, float z)
-{
- struct quaternion roll = {sinf(x * 0.5f), 0, 0, cosf(x * 0.5f)};
- struct quaternion pitch = {0, sinf(y * 0.5f), 0, cosf(y * 0.5f)};
- struct quaternion yaw = {0, 0, sinf(z * 0.5f), cosf(z * 0.5f)};
-
- // Order: y * x * z
- quaternion_mul(q, &pitch, &roll);
- quaternion_mul(q, q, &yaw);
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_slerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
-{
- float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
- if (cosTheta < 0)
- {
- cosTheta = -cosTheta;
- q->x = -b->x;
- q->y = -b->y;
- q->z = -b->z;
- q->w = -b->w;
- }
- else
- {
- *q = *b;
- }
- float scale0 = 1 - t, scale1 = t;
- if ((1 - cosTheta) > 0.001f)
- {
- // use spherical interpolation
- float theta = acosf(cosTheta);
- float sinTheta = sinf(theta);
- scale0 = sinf((1 - t) * theta) / sinTheta;
- scale1 = sinf(t * theta) / sinTheta;
- }
-
- q->x = a->x * scale0 + q->x * scale1;
- q->y = a->y * scale0 + q->y * scale1;
- q->z = a->z * scale0 + q->z * scale1;
- q->w = a->w * scale0 + q->w * scale1;
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_nslerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
-{
- // Normalized linear quaternion interpolation
- // Note: NLERP is faster than SLERP and commutative but does not yield constant velocity
-
- float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
-
- if (cosTheta < 0)
- {
- q->x = a->x + (-b->x - a->x) * t;
- q->y = a->y + (-b->y - a->y) * t;
- q->z = a->z + (-b->z - a->z) * t;
- q->w = a->w + (-b->w - a->w) * t;
- }
- else
- {
- q->x = a->x + (b->x - a->x) * t;
- q->y = a->y + (b->y - a->y) * t;
- q->z = a->z + (b->z - a->z) * t;
- q->w = a->w + (b->w - a->w) * t;
- }
-
- float invLen = 1.0f / sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
-
- q->x *= invLen;
- q->y *= invLen;
- q->z *= invLen;
- q->w *= invLen;
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_inverted(struct quaternion *q)
-{
- float len = q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
- if (len > 0)
- {
- float invLen = -1.0f / len;
- q->x *= invLen;
- q->y *= invLen;
- q->z *= invLen;
- q->w *= invLen;
- q->w = -q->w;
- }
- else
- {
- q->x = q->y = q->z = q->w = 0;
- }
- return q;
-}
-
-// matrix 4*4
-
-#define C m->c
-
-static inline union matrix44 *
-matrix44_identity(union matrix44 *m)
-{
- C[0][0] = 1;
- C[1][0] = 0;
- C[2][0] = 0;
- C[3][0] = 0;
- C[0][1] = 0;
- C[1][1] = 1;
- C[2][1] = 0;
- C[3][1] = 0;
- C[0][2] = 0;
- C[1][2] = 0;
- C[2][2] = 1;
- C[3][2] = 0;
- C[0][3] = 0;
- C[1][3] = 0;
- C[2][3] = 0;
- C[3][3] = 1;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_from_quaternion(union matrix44 *m, const struct quaternion *q)
-{
- // Calculate coefficients
- float x2 = q->x + q->x, y2 = q->y + q->y, z2 = q->z + q->z;
- float xx = q->x * x2, xy = q->x * y2, xz = q->x * z2;
- float yy = q->y * y2, yz = q->y * z2, zz = q->z * z2;
- float wx = q->w * x2, wy = q->w * y2, wz = q->w * z2;
-
- C[0][0] = 1 - (yy + zz);
- C[1][0] = xy + wz;
- C[2][0] = xz - wy;
- C[3][0] = 0;
- C[0][1] = xy - wz;
- C[1][1] = 1 - (xx + zz);
- C[2][1] = yz + wx;
- C[3][1] = 0;
- C[0][2] = xz + wy;
- C[1][2] = yz - wx;
- C[2][2] = 1 - (xx + yy);
- C[3][2] = 0;
- C[0][3] = 0;
- C[1][3] = 0;
- C[2][3] = 0;
- C[3][3] = 1;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_trans(union matrix44 *m, float x, float y, float z)
-{
- matrix44_identity(m);
- C[3][0] = x;
- C[3][1] = y;
- C[3][2] = z;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_scale(union matrix44 *m, float x, float y, float z)
-{
- matrix44_identity(m);
- C[0][0] = x;
- C[1][1] = y;
- C[2][2] = z;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_rot(union matrix44 *m, float x, float y, float z)
-{
- // Rotation order: YXZ [* Vector]
- struct quaternion q;
- quaternion_init(&q, x, y, z);
-
- return matrix44_from_quaternion(m, &q);
-}
-
-#include
-static inline union matrix44 *
-matrix44_rot_axis(union matrix44 *m, const struct vector3 *axis, float angle)
-{
- float t = sinf(angle * 0.5f);
- float x = axis->x * t;
- float y = axis->y * t;
- float z = axis->z * t;
- struct quaternion q = {x, y, z, cosf(angle * 0.5f)};
-
- return matrix44_from_quaternion(m, &q);
-}
-
-static inline union matrix44 *
-matrix44_perspective(union matrix44 *m, float l, float r, float b, float t, float n, float f)
-{
- matrix44_identity(m);
- float *mx = m->x;
-
- mx[0] = 2 * n / (r - l);
- mx[5] = 2 * n / (t - b);
- mx[8] = -(r + l) / (r - l);
- mx[9] = -(t + b) / (t - b);
- mx[10] = (f + n) / (f - n);
- mx[11] = 1;
- mx[14] = -2 * f * n / (f - n);
- mx[15] = 0;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_ortho(union matrix44 *m, float l, float r, float b, float t, float n, float f)
-{
- matrix44_identity(m);
- float *mx = m->x;
-
- mx[0] = 2 / (r - l);
- mx[5] = 2 / (t - b);
- mx[10] = 2 / (f - n);
- mx[12] = -(r + l) / (r - l);
- mx[13] = -(t + b) / (t - b);
- mx[14] = -(f + n) / (f - n);
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_fastmul43(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
-{
- // Note: m may not be the same as m1 or m2
-
- const float *m1x = m1->x;
- const float *m2x = m2->x;
- float *mx = m->x;
-
- mx[0] = m1x[0] * m2x[0] + m1x[1] * m2x[4] + m1x[2] * m2x[8];
- mx[1] = m1x[0] * m2x[1] + m1x[1] * m2x[5] + m1x[2] * m2x[9];
- mx[2] = m1x[0] * m2x[2] + m1x[1] * m2x[6] + m1x[2] * m2x[10];
- mx[3] = 0.0f;
-
- mx[4] = m1x[4] * m2x[0] + m1x[5] * m2x[4] + m1x[6] * m2x[8];
- mx[5] = m1x[4] * m2x[1] + m1x[5] * m2x[5] + m1x[6] * m2x[9];
- mx[6] = m1x[4] * m2x[2] + m1x[5] * m2x[6] + m1x[6] * m2x[10];
- mx[7] = 0.0f;
-
- mx[8] = m1x[8] * m2x[0] + m1x[9] * m2x[4] + m1x[10] * m2x[8];
- mx[9] = m1x[8] * m2x[1] + m1x[9] * m2x[5] + m1x[10] * m2x[9];
- mx[10] = m1x[8] * m2x[2] + m1x[9] * m2x[6] + m1x[10] * m2x[10];
- mx[11] = 0.0f;
-
- mx[12] = m1x[12] * m2x[0] + m1x[13] * m2x[4] + m1x[14] * m2x[8] + m1x[15] * m2x[12];
- mx[13] = m1x[12] * m2x[1] + m1x[13] * m2x[5] + m1x[14] * m2x[9] + m1x[15] * m2x[13];
- mx[14] = m1x[12] * m2x[1] + m1x[13] * m2x[6] + m1x[14] * m2x[10] + m1x[15] * m2x[14];
- mx[15] = 1.0f;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_mul(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
-{
- union matrix44 mf;
- const float *m1x = m1->x;
- const float *m2x = m2->x;
-
- mf.x[0] = m1x[0] * m2x[0] + m1x[1] * m2x[4] + m1x[2] * m2x[8] + m1x[3] * m2x[12];
- mf.x[1] = m1x[0] * m2x[1] + m1x[1] * m2x[5] + m1x[2] * m2x[9] + m1x[3] * m2x[13];
- mf.x[2] = m1x[0] * m2x[2] + m1x[1] * m2x[6] + m1x[2] * m2x[10] + m1x[3] * m2x[14];
- mf.x[3] = m1x[0] * m2x[3] + m1x[1] * m2x[7] + m1x[2] * m2x[11] + m1x[3] * m2x[15];
-
- mf.x[4] = m1x[4] * m2x[0] + m1x[5] * m2x[4] + m1x[6] * m2x[8] + m1x[7] * m2x[12];
- mf.x[5] = m1x[4] * m2x[1] + m1x[5] * m2x[5] + m1x[6] * m2x[9] + m1x[7] * m2x[13];
- mf.x[6] = m1x[4] * m2x[2] + m1x[5] * m2x[6] + m1x[6] * m2x[10] + m1x[7] * m2x[14];
- mf.x[7] = m1x[4] * m2x[3] + m1x[5] * m2x[7] + m1x[6] * m2x[11] + m1x[7] * m2x[15];
-
- mf.x[8] = m1x[8] * m2x[0] + m1x[9] * m2x[4] + m1x[10] * m2x[8] + m1x[11] * m2x[12];
- mf.x[9] = m1x[8] * m2x[1] + m1x[9] * m2x[5] + m1x[10] * m2x[9] + m1x[11] * m2x[13];
- mf.x[10] = m1x[8] * m2x[2] + m1x[9] * m2x[6] + m1x[10] * m2x[10] + m1x[11] * m2x[14];
- mf.x[11] = m1x[8] * m2x[3] + m1x[9] * m2x[7] + m1x[10] * m2x[11] + m1x[11] * m2x[15];
-
- mf.x[12] = m1x[12] * m2x[0] + m1x[13] * m2x[4] + m1x[14] * m2x[8] + m1x[15] * m2x[12];
- mf.x[13] = m1x[12] * m2x[1] + m1x[13] * m2x[5] + m1x[14] * m2x[9] + m1x[15] * m2x[13];
- mf.x[14] = m1x[12] * m2x[2] + m1x[13] * m2x[6] + m1x[14] * m2x[10] + m1x[15] * m2x[14];
- mf.x[15] = m1x[12] * m2x[3] + m1x[13] * m2x[7] + m1x[14] * m2x[11] + m1x[15] * m2x[15];
-
- *m = mf;
-
- return m;
-}
-
-static inline struct vector3 *
-vector3_mul(struct vector3 *v, const union matrix44 *m)
-{
- float x = v->x * C[0][0] + v->y * C[0][1] + v->z * C[0][2] + C[0][3];
- float y = v->x * C[1][0] + v->y * C[1][1] + v->z * C[1][2] + C[1][3];
- float z = v->x * C[2][0] + v->y * C[2][1] + v->z * C[2][2] + C[2][3];
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-static inline struct vector4 *
-vector4_mul(struct vector4 *v, const union matrix44 *m)
-{
- float x = v->x * C[0][0] + v->y * C[0][1] + v->z * C[0][2] + v->w * C[0][3];
- float y = v->x * C[1][0] + v->y * C[1][1] + v->z * C[1][2] + v->w * C[1][3];
- float z = v->x * C[2][0] + v->y * C[2][1] + v->z * C[2][2] + v->w * C[2][3];
- float w = v->x * C[3][0] + v->y * C[3][1] + v->z * C[3][2] + v->w * C[3][3];
-
- v->x = x;
- v->y = y;
- v->z = z;
- v->w = w;
- return v;
-}
-
-static inline struct vector3 *
-vector3_mul33(struct vector3 *v, const union matrix44 *m)
-{
- float x = v->x * C[0][0] + v->y * C[0][1] + v->z * C[0][2];
- float y = v->x * C[1][0] + v->y * C[1][1] + v->z * C[1][2];
- float z = v->x * C[2][0] + v->y * C[2][1] + v->z * C[2][2];
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-static inline union matrix44 *
-matrix44_transposed(union matrix44 *m)
-{
- int x, y;
- for (y = 0; y < 4; ++y)
- {
- for (x = y + 1; x < 4; ++x)
- {
- float tmp = C[x][y];
- C[x][y] = C[y][x];
- C[y][x] = tmp;
- }
- }
-
- return m;
-}
-
-static inline float
-matrix44_determinant(const union matrix44 *m)
-{
- return C[0][3] * C[1][2] * C[2][1] * C[3][0] - C[0][2] * C[1][3] * C[2][1] * C[3][0] - C[0][3] * C[1][1] * C[2][2] * C[3][0] + C[0][1] * C[1][3] * C[2][2] * C[3][0] +
- C[0][2] * C[1][1] * C[2][3] * C[3][0] - C[0][1] * C[1][2] * C[2][3] * C[3][0] - C[0][3] * C[1][2] * C[2][0] * C[3][1] + C[0][2] * C[1][3] * C[2][0] * C[3][1] +
- C[0][3] * C[1][0] * C[2][2] * C[3][1] - C[0][0] * C[1][3] * C[2][2] * C[3][1] - C[0][2] * C[1][0] * C[2][3] * C[3][1] + C[0][0] * C[1][2] * C[2][3] * C[3][1] +
- C[0][3] * C[1][1] * C[2][0] * C[3][2] - C[0][1] * C[1][3] * C[2][0] * C[3][2] - C[0][3] * C[1][0] * C[2][1] * C[3][2] + C[0][0] * C[1][3] * C[2][1] * C[3][2] +
- C[0][1] * C[1][0] * C[2][3] * C[3][2] - C[0][0] * C[1][1] * C[2][3] * C[3][2] - C[0][2] * C[1][1] * C[2][0] * C[3][3] + C[0][1] * C[1][2] * C[2][0] * C[3][3] +
- C[0][2] * C[1][0] * C[2][1] * C[3][3] - C[0][0] * C[1][2] * C[2][1] * C[3][3] - C[0][1] * C[1][0] * C[2][2] * C[3][3] + C[0][0] * C[1][1] * C[2][2] * C[3][3];
-}
-
-static inline union matrix44 *
-matrix44_inverted(union matrix44 *dst, const union matrix44 *m)
-{
- float d = matrix44_determinant(m);
- if (d == 0)
- {
- *dst = *m;
- return dst;
- }
- d = 1.0f / d;
-
- dst->c[0][0] = d * (C[1][2] * C[2][3] * C[3][1] - C[1][3] * C[2][2] * C[3][1] + C[1][3] * C[2][1] * C[3][2] - C[1][1] * C[2][3] * C[3][2] - C[1][2] * C[2][1] * C[3][3] + C[1][1] * C[2][2] * C[3][3]);
- dst->c[0][1] = d * (C[0][3] * C[2][2] * C[3][1] - C[0][2] * C[2][3] * C[3][1] - C[0][3] * C[2][1] * C[3][2] + C[0][1] * C[2][3] * C[3][2] + C[0][2] * C[2][1] * C[3][3] - C[0][1] * C[2][2] * C[3][3]);
- dst->c[0][2] = d * (C[0][2] * C[1][3] * C[3][1] - C[0][3] * C[1][2] * C[3][1] + C[0][3] * C[1][1] * C[3][2] - C[0][1] * C[1][3] * C[3][2] - C[0][2] * C[1][1] * C[3][3] + C[0][1] * C[1][2] * C[3][3]);
- dst->c[0][3] = d * (C[0][3] * C[1][2] * C[2][1] - C[0][2] * C[1][3] * C[2][1] - C[0][3] * C[1][1] * C[2][2] + C[0][1] * C[1][3] * C[2][2] + C[0][2] * C[1][1] * C[2][3] - C[0][1] * C[1][2] * C[2][3]);
- dst->c[1][0] = d * (C[1][3] * C[2][2] * C[3][0] - C[1][2] * C[2][3] * C[3][0] - C[1][3] * C[2][0] * C[3][2] + C[1][0] * C[2][3] * C[3][2] + C[1][2] * C[2][0] * C[3][3] - C[1][0] * C[2][2] * C[3][3]);
- dst->c[1][1] = d * (C[0][2] * C[2][3] * C[3][0] - C[0][3] * C[2][2] * C[3][0] + C[0][3] * C[2][0] * C[3][2] - C[0][0] * C[2][3] * C[3][2] - C[0][2] * C[2][0] * C[3][3] + C[0][0] * C[2][2] * C[3][3]);
- dst->c[1][2] = d * (C[0][3] * C[1][2] * C[3][0] - C[0][2] * C[1][3] * C[3][0] - C[0][3] * C[1][0] * C[3][2] + C[0][0] * C[1][3] * C[3][2] + C[0][2] * C[1][0] * C[3][3] - C[0][0] * C[1][2] * C[3][3]);
- dst->c[1][3] = d * (C[0][2] * C[1][3] * C[2][0] - C[0][3] * C[1][2] * C[2][0] + C[0][3] * C[1][0] * C[2][2] - C[0][0] * C[1][3] * C[2][2] - C[0][2] * C[1][0] * C[2][3] + C[0][0] * C[1][2] * C[2][3]);
- dst->c[2][0] = d * (C[1][1] * C[2][3] * C[3][0] - C[1][3] * C[2][1] * C[3][0] + C[1][3] * C[2][0] * C[3][1] - C[1][0] * C[2][3] * C[3][1] - C[1][1] * C[2][0] * C[3][3] + C[1][0] * C[2][1] * C[3][3]);
- dst->c[2][1] = d * (C[0][3] * C[2][1] * C[3][0] - C[0][1] * C[2][3] * C[3][0] - C[0][3] * C[2][0] * C[3][1] + C[0][0] * C[2][3] * C[3][1] + C[0][1] * C[2][0] * C[3][3] - C[0][0] * C[2][1] * C[3][3]);
- dst->c[2][2] = d * (C[0][1] * C[1][3] * C[3][0] - C[0][3] * C[1][1] * C[3][0] + C[0][3] * C[1][0] * C[3][1] - C[0][0] * C[1][3] * C[3][1] - C[0][1] * C[1][0] * C[3][3] + C[0][0] * C[1][1] * C[3][3]);
- dst->c[2][3] = d * (C[0][3] * C[1][1] * C[2][0] - C[0][1] * C[1][3] * C[2][0] - C[0][3] * C[1][0] * C[2][1] + C[0][0] * C[1][3] * C[2][1] + C[0][1] * C[1][0] * C[2][3] - C[0][0] * C[1][1] * C[2][3]);
- dst->c[3][0] = d * (C[1][2] * C[2][1] * C[3][0] - C[1][1] * C[2][2] * C[3][0] - C[1][2] * C[2][0] * C[3][1] + C[1][0] * C[2][2] * C[3][1] + C[1][1] * C[2][0] * C[3][2] - C[1][0] * C[2][1] * C[3][2]);
- dst->c[3][1] = d * (C[0][1] * C[2][2] * C[3][0] - C[0][2] * C[2][1] * C[3][0] + C[0][2] * C[2][0] * C[3][1] - C[0][0] * C[2][2] * C[3][1] - C[0][1] * C[2][0] * C[3][2] + C[0][0] * C[2][1] * C[3][2]);
- dst->c[3][2] = d * (C[0][2] * C[1][1] * C[3][0] - C[0][1] * C[1][2] * C[3][0] - C[0][2] * C[1][0] * C[3][1] + C[0][0] * C[1][2] * C[3][1] + C[0][1] * C[1][0] * C[3][2] - C[0][0] * C[1][1] * C[3][2]);
- dst->c[3][3] = d * (C[0][1] * C[1][2] * C[2][0] - C[0][2] * C[1][1] * C[2][0] + C[0][2] * C[1][0] * C[2][1] - C[0][0] * C[1][2] * C[2][1] - C[0][1] * C[1][0] * C[2][2] + C[0][0] * C[1][1] * C[2][2]);
-
- return dst;
-}
-
-static inline struct vector3 *
-matrix44_gettrans(const union matrix44 *m, struct vector3 *trans)
-{
- // Getting translation is trivial
- trans->x = C[3][0];
- trans->y = C[3][1];
- trans->z = C[3][2];
-
- return trans;
-}
-
-static inline struct vector3 *
-matrix44_getscale(const union matrix44 *m, struct vector3 *scale)
-{
- // Scale is length of columns
- scale->x = sqrtf(C[0][0] * C[0][0] + C[0][1] * C[0][1] + C[0][2] * C[0][2]);
- scale->y = sqrtf(C[1][0] * C[1][0] + C[1][1] * C[1][1] + C[1][2] * C[1][2]);
- scale->z = sqrtf(C[2][0] * C[2][0] + C[2][1] * C[2][1] + C[2][2] * C[2][2]);
-
- return scale;
-}
-
-// NOTICE: Huanzai
-// this function may be need to convert from right to left handed coordinate
-static inline void
-matrix44_decompose(const union matrix44 *m, struct vector3 *trans, struct vector3 *rot, struct vector3 *scale)
-{
- matrix44_gettrans(m, trans);
- matrix44_getscale(m, scale);
-
- if (scale->x == 0 || scale->y == 0 || scale->z == 0)
- {
- rot->x = 0;
- rot->y = 0;
- rot->z = 0;
- return;
- }
-
- // Detect negative scale with determinant and flip one arbitrary axis
- if (matrix44_determinant(m) < 0)
- scale->x = -scale->x;
-
- // Combined rotation matrix YXZ
- //
- // Cos[y]*Cos[z]+Sin[x]*Sin[y]*Sin[z] Cos[z]*Sin[x]*Sin[y]-Cos[y]*Sin[z] Cos[x]*Sin[y]
- // Cos[x]*Sin[z] Cos[x]*Cos[z] -Sin[x]
- // -Cos[z]*Sin[y]+Cos[y]*Sin[x]*Sin[z] Cos[y]*Cos[z]*Sin[x]+Sin[y]*Sin[z] Cos[x]*Cos[y]
-
- rot->x = asinf(-C[2][1] / scale->z);
-
- // Special case: Cos[x] == 0 (when Sin[x] is +/-1)
- float f = fabsf(C[2][1] / scale->z);
-
- if (f > 0.999f && f < 1.001f)
- {
- // Pin arbitrarily one of y or z to zero
- // Mathematical equivalent of gimbal lock
- rot->y = 0;
-
- // Now: Cos[x] = 0, Sin[x] = +/-1, Cos[y] = 1, Sin[y] = 0
- // => m[0][0] = Cos[z] and m[1][0] = Sin[z]
- rot->z = atan2f(-C[1][0] / scale->y, C[0][0] / scale->x);
- }
- else
- {
- // Standard case
- rot->y = atan2f(C[2][0] / scale->z, C[2][2] / scale->z);
- rot->z = atan2f(C[0][1] / scale->x, C[1][1] / scale->y);
- }
-}
-
-static inline float *
-matrix44_to33(const union matrix44 *m, float m33[9])
-{
- m33[0] = C[0][0];
- m33[1] = C[0][1];
- m33[2] = C[0][2];
- m33[3] = C[1][0];
- m33[4] = C[1][1];
- m33[5] = C[1][2];
- m33[6] = C[2][0];
- m33[7] = C[2][1];
- m33[8] = C[2][2];
-
- return m33;
-}
-
-#undef C
-
-// plane
-
-static inline struct plane *
-plane_init(struct plane *p, const struct vector3 *normal, float d)
-{
- p->normal = *normal;
- // normalize
- float invLen = 1.0f / vector3_length(normal);
- p->normal.x *= invLen;
- p->normal.y *= invLen;
- p->normal.z *= invLen;
- p->dist = d * invLen;
-
- return p;
-}
-
-static inline struct plane *
-plane_init_dot3(struct plane *p, const struct vector3 *v0, const struct vector3 *v1, const struct vector3 *v2)
-{
- struct vector3 a, b;
- vector3_vector(&a, v1, v0);
- vector3_vector(&b, v2, v0);
-
- vector3_cross(&p->normal, &a, &b);
- vector3_normalize(&p->normal);
- p->dist = -vector3_dot(&p->normal, v0);
-
- return p;
-}
-
-static inline float
-plane_dist(const struct plane *p, const struct vector3 *v)
-{
- float d = vector3_dot(&p->normal, v);
- return d + p->dist;
-}
-
-// Intersection
-
-static inline struct vector3 *
-intersection_raytriangle(const struct vector3 *rayOrig, const struct vector3 *rayDir,
- const struct vector3 *vert0, const struct vector3 *vert1, const struct vector3 *vert2,
- struct vector3 *intsPoint)
-{
- // Idea: Tomas Moeller and Ben Trumbore
- // in Fast, Minimum Storage Ray/Triangle Intersection
-
- // Find vectors for two edges sharing vert0
- struct vector3 edge1, edge2;
- vector3_vector(&edge1, vert1, vert0);
- vector3_vector(&edge2, vert2, vert0);
-
- // Begin calculating determinant - also used to calculate U parameter
- struct vector3 pvec;
- vector3_cross(&pvec, rayDir, &edge2);
-
- // If determinant is near zero, ray lies in plane of triangle
- float det = vector3_dot(&edge1, &pvec);
-
- // *** Culling branch ***
- /*if( det < FLT_EPSILON )
- return NULL;
-
- // Calculate distance from vert0 to ray origin
- struct vector3 tvec;
- vector3_vector(&tvec, rayOrig, &vert0);
-
- // Calculate U parameter and test bounds
- float u = vector3_dot(&tvec, &pvec);
- if (u < 0 || u > det )
- return NULL;
-
- // Prepare to test V parameter
- struct vector3 qvec;
- vector3_cross(&qvec, &tvec, &edge1);
-
- // Calculate V parameter and test bounds
- float v = vector3_dot(rayDir, &qvec);
- if (v < 0 || u + v > det )
- return NULL;
-
- // Calculate t, scale parameters, ray intersects triangle
- float t = vector3_dot(&edge2, &qvec ) / det;*/
-
- // *** Non-culling branch ***
- if (det > -FLT_EPSILON && det < FLT_EPSILON)
- return 0;
- float inv_det = 1.0f / det;
-
- // Calculate distance from vert0 to ray origin
- struct vector3 tvec;
- vector3_vector(&tvec, rayOrig, vert0);
-
- // Calculate U parameter and test bounds
- float u = vector3_dot(&tvec, &pvec) * inv_det;
- if (u < 0.0f || u > 1.0f)
- return 0;
-
- // Prepare to test V parameter
- struct vector3 qvec;
- vector3_cross(&qvec, &tvec, &edge1);
-
- // Calculate V parameter and test bounds
- float v = vector3_dot(rayDir, &qvec) * inv_det;
- if (v < 0.0f || u + v > 1.0f)
- return 0;
-
- // Calculate t, ray intersects triangle
- float t = vector3_dot(&edge2, &qvec) * inv_det;
-
- // Calculate intersection point and test ray length and direction
- intsPoint->x = rayOrig->x + rayDir->x * t;
- intsPoint->y = rayOrig->y + rayDir->y * t;
- intsPoint->z = rayOrig->z + rayDir->z * t;
-
- struct vector3 vec;
- vector3_vector(&vec, intsPoint, rayOrig);
- if (vector3_dot(&vec, rayDir) < 0 || vector3_length(&vec) > vector3_length(rayDir))
- return NULL;
-
- return intsPoint;
-}
-
-static inline float
-minf(float a, float b)
-{
- return a < b ? a : b;
-}
-
-static inline float
-maxf(float a, float b)
-{
- return a > b ? a : b;
-}
-
-static inline int
-intersection_rayAABB(const struct vector3 *rayOrig, const struct vector3 *rayDir,
- const struct vector3 *mins, const struct vector3 *maxs)
-{
- // SLAB based optimized ray/AABB intersection routine
- // Idea taken from http://ompf.org/ray/
-
- float l1 = (mins->x - rayOrig->x) / rayDir->x;
- float l2 = (maxs->x - rayOrig->x) / rayDir->x;
- float lmin = minf(l1, l2);
- float lmax = maxf(l1, l2);
-
- l1 = (mins->y - rayOrig->y) / rayDir->y;
- l2 = (maxs->y - rayOrig->y) / rayDir->y;
- lmin = maxf(minf(l1, l2), lmin);
- lmax = minf(maxf(l1, l2), lmax);
-
- l1 = (mins->z - rayOrig->z) / rayDir->z;
- l2 = (maxs->z - rayOrig->z) / rayDir->z;
- lmin = maxf(minf(l1, l2), lmin);
- lmax = minf(maxf(l1, l2), lmax);
-
- if ((lmax >= 0.0f) & (lmax >= lmin))
- {
- // Consider length
- const struct vector3 rayDest = {rayOrig->x + rayDir->x, rayOrig->y + rayDir->y, rayOrig->z + rayDir->z};
- const struct vector3 rayMins = {minf(rayDest.x, rayOrig->x), minf(rayDest.y, rayOrig->y), minf(rayDest.z, rayOrig->z)};
- const struct vector3 rayMaxs = {maxf(rayDest.x, rayOrig->x), maxf(rayDest.y, rayOrig->y), maxf(rayDest.z, rayOrig->z)};
- return (rayMins.x < maxs->x) && (rayMaxs.x > mins->x) &&
- (rayMins.y < maxs->y) && (rayMaxs.y > mins->y) &&
- (rayMins.z < maxs->z) && (rayMaxs.z > mins->z);
- }
- else
- {
- return 0;
- }
-}
-
-static inline float
-vector3_distAABB(const struct vector3 *pos, const struct vector3 *mins, const struct vector3 *maxs)
-{
- struct vector3 center;
- struct vector3 extent;
- center.x = (mins->x + maxs->x) * 0.5f;
- center.y = (mins->y + maxs->y) * 0.5f;
- center.z = (mins->z + maxs->z) * 0.5f;
-
- extent.x = (maxs->x - mins->x) * 0.5f;
- extent.y = (maxs->y - mins->y) * 0.5f;
- extent.z = (maxs->z - mins->z) * 0.5f;
-
- struct vector3 nearestVec;
- nearestVec.x = maxf(0, fabsf(pos->x - center.x) - extent.x);
- nearestVec.y = maxf(0, fabsf(pos->y - center.y) - extent.y);
- nearestVec.z = maxf(0, fabsf(pos->z - center.z) - extent.z);
-
- return vector3_length(&nearestVec);
-}
-
-#endif
diff --git a/framework/lualib-src/lua-math3d/math3d-right.h b/framework/lualib-src/lua-math3d/math3d-right.h
deleted file mode 100644
index e01fcbb..0000000
--- a/framework/lualib-src/lua-math3d/math3d-right.h
+++ /dev/null
@@ -1,835 +0,0 @@
-// This is a rewrite version (in C) from Horde3D (utMath.h) , http://www.horde3d.org
-// Math library
-//
-// Coordinate system is right-handed with positive y as up axis
-//
-
-#ifndef ejoy3d_math_h
-#define ejoy3d_math_h
-
-#include
-#include
-#include
-
-struct vector3
-{
- float x, y, z;
-};
-
-struct vector4
-{
- float x, y, z, w;
-};
-
-struct quaternion
-{
- float x, y, z, w;
-};
-
-union matrix44
-{
- float c[4][4];
- float x[16];
-};
-
-struct plane
-{
- struct vector3 normal;
- float dist;
-};
-
-// vector
-
-static inline float *
-vector3_array(struct vector3 *v)
-{
- return (float *)v;
-}
-
-static inline float *
-vector4_array(struct vector4 *v)
-{
- return (float *)v;
-}
-
-static inline float
-vector3_dot(const struct vector3 *a, const struct vector3 *b)
-{
- return a->x * b->x + a->y * b->y + a->z * b->z;
-}
-
-static inline struct vector3 *
-vector3_cross(struct vector3 *v, const struct vector3 *a, const struct vector3 *b)
-{
- float x = a->y * b->z - a->z * b->y;
- float y = a->z * b->x - a->x * b->z;
- float z = a->x * b->y - a->y * b->x;
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-static inline struct vector3 *
-vector3_vector(struct vector3 *v, const struct vector3 *p1, const struct vector3 *p2)
-{
- v->x = p1->x - p2->x;
- v->y = p1->y - p2->y;
- v->z = p1->z - p2->z;
-
- return v;
-}
-
-static inline float
-vector3_length(const struct vector3 *v)
-{
- return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
-}
-
-static inline struct vector3 *
-vector3_normalize(struct vector3 *v)
-{
- float invLen = 1.0f / vector3_length(v);
- v->x *= invLen;
- v->y *= invLen;
- v->z *= invLen;
-
- return v;
-}
-
-static inline struct vector3 *
-vector3_to_rotation(struct vector3 *v, const struct vector3 *r)
-{
- // Assumes that the unrotated view vector is (0, 0, -1)
- v->x = v->y = v->z = 0;
- if (r->y != 0)
- {
- v->x = atan2f(r->y, sqrtf(r->x * r->x + r->z * r->z));
- }
- if (r->x != 0 || r->z != 0)
- {
- v->y = atan2f(-r->x, -r->z);
- }
-
- return v;
-}
-
-static inline struct vector3 *
-vector3_lerp(struct vector3 *v, const struct vector3 *a, const struct vector3 *b, float f)
-{
- float x = a->x + (b->x - a->x) * f;
- float y = a->y + (b->y - a->y) * f;
- float z = a->z + (b->z - a->z) * f;
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-// quaternion
-
-static inline struct quaternion *
-quaternion_mul(struct quaternion *q, const struct quaternion *a, const struct quaternion *b)
-{
- float x = a->y * b->z - a->z * b->y + b->x * a->w + a->x * b->w;
- float y = a->z * b->x - a->x * b->z + b->y * a->w + a->y * b->w;
- float z = a->x * b->y - a->y * b->x + b->z * a->w + a->z * b->w;
- float w = a->w * b->w - (a->x * b->x + a->y * b->y + a->z * b->z);
-
- q->x = x;
- q->y = y;
- q->z = z;
- q->w = w;
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_init(struct quaternion *q, float x, float y, float z)
-{
- struct quaternion roll = {sinf(x * 0.5f), 0, 0, cosf(x * 0.5f)};
- struct quaternion pitch = {0, sinf(y * 0.5f), 0, cosf(y * 0.5f)};
- struct quaternion yaw = {0, 0, sinf(z * 0.5f), cosf(z * 0.5f)};
-
- // Order: y * x * z
- quaternion_mul(q, &pitch, &roll);
- quaternion_mul(q, q, &yaw);
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_slerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
-{
- float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
- if (cosTheta < 0)
- {
- cosTheta = -cosTheta;
- q->x = -b->x;
- q->y = -b->y;
- q->z = -b->z;
- q->w = -b->w;
- }
- else
- {
- *q = *b;
- }
- float scale0 = 1 - t, scale1 = t;
- if ((1 - cosTheta) > 0.001f)
- {
- // use spherical interpolation
- float theta = acosf(cosTheta);
- float sinTheta = sinf(theta);
- scale0 = sinf((1 - t) * theta) / sinTheta;
- scale1 = sinf(t * theta) / sinTheta;
- }
-
- q->x = a->x * scale0 + q->x * scale1;
- q->y = a->y * scale0 + q->y * scale1;
- q->z = a->z * scale0 + q->z * scale1;
- q->w = a->w * scale0 + q->w * scale1;
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_nslerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
-{
- // Normalized linear quaternion interpolation
- // Note: NLERP is faster than SLERP and commutative but does not yield constant velocity
-
- float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
-
- if (cosTheta < 0)
- {
- q->x = a->x + (-b->x - a->x) * t;
- q->y = a->y + (-b->y - a->y) * t;
- q->z = a->z + (-b->z - a->z) * t;
- q->w = a->w + (-b->w - a->w) * t;
- }
- else
- {
- q->x = a->x + (b->x - a->x) * t;
- q->y = a->y + (b->y - a->y) * t;
- q->z = a->z + (b->z - a->z) * t;
- q->w = a->w + (b->w - a->w) * t;
- }
-
- float invLen = 1.0f / sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
-
- q->x *= invLen;
- q->y *= invLen;
- q->z *= invLen;
- q->w *= invLen;
-
- return q;
-}
-
-static inline struct quaternion *
-quaternion_inverted(struct quaternion *q)
-{
- float len = q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
- if (len > 0)
- {
- float invLen = -1.0f / len;
- q->x *= invLen;
- q->y *= invLen;
- q->z *= invLen;
- q->w *= invLen;
- q->w = -q->w;
- }
- else
- {
- q->x = q->y = q->z = q->w = 0;
- }
- return q;
-}
-
-// matrix 4*4
-
-#define C m->c
-
-static inline union matrix44 *
-matrix44_identity(union matrix44 *m)
-{
- C[0][0] = 1;
- C[1][0] = 0;
- C[2][0] = 0;
- C[3][0] = 0;
- C[0][1] = 0;
- C[1][1] = 1;
- C[2][1] = 0;
- C[3][1] = 0;
- C[0][2] = 0;
- C[1][2] = 0;
- C[2][2] = 1;
- C[3][2] = 0;
- C[0][3] = 0;
- C[1][3] = 0;
- C[2][3] = 0;
- C[3][3] = 1;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_from_quaternion(union matrix44 *m, const struct quaternion *q)
-{
- // Calculate coefficients
- float x2 = q->x + q->x, y2 = q->y + q->y, z2 = q->z + q->z;
- float xx = q->x * x2, xy = q->x * y2, xz = q->x * z2;
- float yy = q->y * y2, yz = q->y * z2, zz = q->z * z2;
- float wx = q->w * x2, wy = q->w * y2, wz = q->w * z2;
-
- C[0][0] = 1 - (yy + zz);
- C[1][0] = xy - wz;
- C[2][0] = xz + wy;
- C[3][0] = 0;
- C[0][1] = xy + wz;
- C[1][1] = 1 - (xx + zz);
- C[2][1] = yz - wx;
- C[3][1] = 0;
- C[0][2] = xz - wy;
- C[1][2] = yz + wx;
- C[2][2] = 1 - (xx + yy);
- C[3][2] = 0;
- C[0][3] = 0;
- C[1][3] = 0;
- C[2][3] = 0;
- C[3][3] = 1;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_trans(union matrix44 *m, float x, float y, float z)
-{
- matrix44_identity(m);
- C[3][0] = x;
- C[3][1] = y;
- C[3][2] = z;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_scale(union matrix44 *m, float x, float y, float z)
-{
- matrix44_identity(m);
- C[0][0] = x;
- C[1][1] = y;
- C[2][2] = z;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_rot(union matrix44 *m, float x, float y, float z)
-{
- // Rotation order: YXZ [* Vector]
- struct quaternion q;
- quaternion_init(&q, x, y, z);
-
- return matrix44_from_quaternion(m, &q);
-}
-
-static inline union matrix44 *
-matrix44_rot_axis(union matrix44 *m, const struct vector3 *axis, float angle)
-{
- float t = sinf(angle * 0.5f);
- float x = axis->x * t;
- float y = axis->y * t;
- float z = axis->z * t;
- struct quaternion q = {x, y, z, cosf(angle * 0.5f)};
-
- return matrix44_from_quaternion(m, &q);
-}
-
-static inline union matrix44 *
-matrix44_perspective(union matrix44 *m, float l, float r, float b, float t, float n, float f)
-{
- matrix44_identity(m);
- float *mx = m->x;
-
- mx[0] = 2 * n / (r - l);
- mx[5] = 2 * n / (t - b);
- mx[8] = (r + l) / (r - l);
- mx[9] = (t + b) / (t - b);
- mx[10] = -(f + n) / (f - n);
- mx[11] = -1;
- mx[14] = -2 * f * n / (f - n);
- mx[15] = 0;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_ortho(union matrix44 *m, float l, float r, float b, float t, float n, float f)
-{
- matrix44_identity(m);
- float *mx = m->x;
-
- mx[0] = 2 / (r - l);
- mx[5] = 2 / (t - b);
- mx[10] = -2 / (f - n);
- mx[12] = -(r + l) / (r - l);
- mx[13] = -(t + b) / (t - b);
- mx[14] = -(f + n) / (f - n);
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_fastmul43(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
-{
- // Note: m may not be the same as m1 or m2
-
- const float *m1x = m1->x;
- const float *m2x = m2->x;
- float *mx = m->x;
-
- mx[0] = m1x[0] * m2x[0] + m1x[4] * m2x[1] + m1x[8] * m2x[2];
- mx[1] = m1x[1] * m2x[0] + m1x[5] * m2x[1] + m1x[9] * m2x[2];
- mx[2] = m1x[2] * m2x[0] + m1x[6] * m2x[1] + m1x[10] * m2x[2];
- mx[3] = 0.0f;
-
- mx[4] = m1x[0] * m2x[4] + m1x[4] * m2x[5] + m1x[8] * m2x[6];
- mx[5] = m1x[1] * m2x[4] + m1x[5] * m2x[5] + m1x[9] * m2x[6];
- mx[6] = m1x[2] * m2x[4] + m1x[6] * m2x[5] + m1x[10] * m2x[6];
- mx[7] = 0.0f;
-
- mx[8] = m1x[0] * m2x[8] + m1x[4] * m2x[9] + m1x[8] * m2x[10];
- mx[9] = m1x[1] * m2x[8] + m1x[5] * m2x[9] + m1x[9] * m2x[10];
- mx[10] = m1x[2] * m2x[8] + m1x[6] * m2x[9] + m1x[10] * m2x[10];
- mx[11] = 0.0f;
-
- mx[12] = m1x[0] * m2x[12] + m1x[4] * m2x[13] + m1x[8] * m2x[14] + m1x[12] * m2x[15];
- mx[13] = m1x[1] * m2x[12] + m1x[5] * m2x[13] + m1x[9] * m2x[14] + m1x[13] * m2x[15];
- mx[14] = m1x[2] * m2x[12] + m1x[6] * m2x[13] + m1x[10] * m2x[14] + m1x[14] * m2x[15];
- mx[15] = 1.0f;
-
- return m;
-}
-
-static inline union matrix44 *
-matrix44_mul(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
-{
- union matrix44 mf;
- const float *m1x = m1->x;
- const float *m2x = m2->x;
-
- mf.x[0] = m1x[0] * m2x[0] + m1x[4] * m2x[1] + m1x[8] * m2x[2] + m1x[12] * m2x[3];
- mf.x[1] = m1x[1] * m2x[0] + m1x[5] * m2x[1] + m1x[9] * m2x[2] + m1x[13] * m2x[3];
- mf.x[2] = m1x[2] * m2x[0] + m1x[6] * m2x[1] + m1x[10] * m2x[2] + m1x[14] * m2x[3];
- mf.x[3] = m1x[3] * m2x[0] + m1x[7] * m2x[1] + m1x[11] * m2x[2] + m1x[15] * m2x[3];
-
- mf.x[4] = m1x[0] * m2x[4] + m1x[4] * m2x[5] + m1x[8] * m2x[6] + m1x[12] * m2x[7];
- mf.x[5] = m1x[1] * m2x[4] + m1x[5] * m2x[5] + m1x[9] * m2x[6] + m1x[13] * m2x[7];
- mf.x[6] = m1x[2] * m2x[4] + m1x[6] * m2x[5] + m1x[10] * m2x[6] + m1x[14] * m2x[7];
- mf.x[7] = m1x[3] * m2x[4] + m1x[7] * m2x[5] + m1x[11] * m2x[6] + m1x[15] * m2x[7];
-
- mf.x[8] = m1x[0] * m2x[8] + m1x[4] * m2x[9] + m1x[8] * m2x[10] + m1x[12] * m2x[11];
- mf.x[9] = m1x[1] * m2x[8] + m1x[5] * m2x[9] + m1x[9] * m2x[10] + m1x[13] * m2x[11];
- mf.x[10] = m1x[2] * m2x[8] + m1x[6] * m2x[9] + m1x[10] * m2x[10] + m1x[14] * m2x[11];
- mf.x[11] = m1x[3] * m2x[8] + m1x[7] * m2x[9] + m1x[11] * m2x[10] + m1x[15] * m2x[11];
-
- mf.x[12] = m1x[0] * m2x[12] + m1x[4] * m2x[13] + m1x[8] * m2x[14] + m1x[12] * m2x[15];
- mf.x[13] = m1x[1] * m2x[12] + m1x[5] * m2x[13] + m1x[9] * m2x[14] + m1x[13] * m2x[15];
- mf.x[14] = m1x[2] * m2x[12] + m1x[6] * m2x[13] + m1x[10] * m2x[14] + m1x[14] * m2x[15];
- mf.x[15] = m1x[3] * m2x[12] + m1x[7] * m2x[13] + m1x[11] * m2x[14] + m1x[15] * m2x[15];
-
- *m = mf;
-
- return m;
-}
-
-// vector * matrix
-
-static inline struct vector3 *
-vector3_mul(struct vector3 *v, const union matrix44 *m)
-{
- float x = v->x * C[0][0] + v->y * C[1][0] + v->z * C[2][0] + C[3][0];
- float y = v->x * C[0][1] + v->y * C[1][1] + v->z * C[2][1] + C[3][1];
- float z = v->x * C[0][2] + v->y * C[1][2] + v->z * C[2][2] + C[3][2];
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-static inline struct vector4 *
-vector4_mul(struct vector4 *v, const union matrix44 *m)
-{
- float x = v->x * C[0][0] + v->y * C[1][0] + v->z * C[2][0] + v->w * C[3][0];
- float y = v->x * C[0][1] + v->y * C[1][1] + v->z * C[2][1] + v->w * C[3][1];
- float z = v->x * C[0][2] + v->y * C[1][2] + v->z * C[2][2] + v->w * C[3][2];
- float w = v->x * C[0][3] + v->y * C[1][3] + v->z * C[2][3] + v->w * C[3][3];
-
- v->x = x;
- v->y = y;
- v->z = z;
- v->w = w;
- return v;
-}
-
-static inline struct vector3 *
-vector3_mul33(struct vector3 *v, const union matrix44 *m)
-{
- float x = v->x * C[0][0] + v->y * C[1][0] + v->z * C[2][0];
- float y = v->x * C[0][1] + v->y * C[1][1] + v->z * C[2][1];
- float z = v->x * C[0][2] + v->y * C[1][2] + v->z * C[2][2];
-
- v->x = x;
- v->y = y;
- v->z = z;
-
- return v;
-}
-
-static inline union matrix44 *
-matrix44_transposed(union matrix44 *m)
-{
- int x, y;
- for (y = 0; y < 4; ++y)
- {
- for (x = y + 1; x < 4; ++x)
- {
- float tmp = C[x][y];
- C[x][y] = C[y][x];
- C[y][x] = tmp;
- }
- }
-
- return m;
-}
-
-static inline float
-matrix44_determinant(const union matrix44 *m)
-{
- return C[0][3] * C[1][2] * C[2][1] * C[3][0] - C[0][2] * C[1][3] * C[2][1] * C[3][0] - C[0][3] * C[1][1] * C[2][2] * C[3][0] + C[0][1] * C[1][3] * C[2][2] * C[3][0] +
- C[0][2] * C[1][1] * C[2][3] * C[3][0] - C[0][1] * C[1][2] * C[2][3] * C[3][0] - C[0][3] * C[1][2] * C[2][0] * C[3][1] + C[0][2] * C[1][3] * C[2][0] * C[3][1] +
- C[0][3] * C[1][0] * C[2][2] * C[3][1] - C[0][0] * C[1][3] * C[2][2] * C[3][1] - C[0][2] * C[1][0] * C[2][3] * C[3][1] + C[0][0] * C[1][2] * C[2][3] * C[3][1] +
- C[0][3] * C[1][1] * C[2][0] * C[3][2] - C[0][1] * C[1][3] * C[2][0] * C[3][2] - C[0][3] * C[1][0] * C[2][1] * C[3][2] + C[0][0] * C[1][3] * C[2][1] * C[3][2] +
- C[0][1] * C[1][0] * C[2][3] * C[3][2] - C[0][0] * C[1][1] * C[2][3] * C[3][2] - C[0][2] * C[1][1] * C[2][0] * C[3][3] + C[0][1] * C[1][2] * C[2][0] * C[3][3] +
- C[0][2] * C[1][0] * C[2][1] * C[3][3] - C[0][0] * C[1][2] * C[2][1] * C[3][3] - C[0][1] * C[1][0] * C[2][2] * C[3][3] + C[0][0] * C[1][1] * C[2][2] * C[3][3];
-}
-
-static inline union matrix44 *
-matrix44_inverted(union matrix44 *dst, const union matrix44 *m)
-{
- float d = matrix44_determinant(m);
- if (d == 0)
- {
- *dst = *m;
- return dst;
- }
- d = 1.0f / d;
-
- dst->c[0][0] = d * (C[1][2] * C[2][3] * C[3][1] - C[1][3] * C[2][2] * C[3][1] + C[1][3] * C[2][1] * C[3][2] - C[1][1] * C[2][3] * C[3][2] - C[1][2] * C[2][1] * C[3][3] + C[1][1] * C[2][2] * C[3][3]);
- dst->c[0][1] = d * (C[0][3] * C[2][2] * C[3][1] - C[0][2] * C[2][3] * C[3][1] - C[0][3] * C[2][1] * C[3][2] + C[0][1] * C[2][3] * C[3][2] + C[0][2] * C[2][1] * C[3][3] - C[0][1] * C[2][2] * C[3][3]);
- dst->c[0][2] = d * (C[0][2] * C[1][3] * C[3][1] - C[0][3] * C[1][2] * C[3][1] + C[0][3] * C[1][1] * C[3][2] - C[0][1] * C[1][3] * C[3][2] - C[0][2] * C[1][1] * C[3][3] + C[0][1] * C[1][2] * C[3][3]);
- dst->c[0][3] = d * (C[0][3] * C[1][2] * C[2][1] - C[0][2] * C[1][3] * C[2][1] - C[0][3] * C[1][1] * C[2][2] + C[0][1] * C[1][3] * C[2][2] + C[0][2] * C[1][1] * C[2][3] - C[0][1] * C[1][2] * C[2][3]);
- dst->c[1][0] = d * (C[1][3] * C[2][2] * C[3][0] - C[1][2] * C[2][3] * C[3][0] - C[1][3] * C[2][0] * C[3][2] + C[1][0] * C[2][3] * C[3][2] + C[1][2] * C[2][0] * C[3][3] - C[1][0] * C[2][2] * C[3][3]);
- dst->c[1][1] = d * (C[0][2] * C[2][3] * C[3][0] - C[0][3] * C[2][2] * C[3][0] + C[0][3] * C[2][0] * C[3][2] - C[0][0] * C[2][3] * C[3][2] - C[0][2] * C[2][0] * C[3][3] + C[0][0] * C[2][2] * C[3][3]);
- dst->c[1][2] = d * (C[0][3] * C[1][2] * C[3][0] - C[0][2] * C[1][3] * C[3][0] - C[0][3] * C[1][0] * C[3][2] + C[0][0] * C[1][3] * C[3][2] + C[0][2] * C[1][0] * C[3][3] - C[0][0] * C[1][2] * C[3][3]);
- dst->c[1][3] = d * (C[0][2] * C[1][3] * C[2][0] - C[0][3] * C[1][2] * C[2][0] + C[0][3] * C[1][0] * C[2][2] - C[0][0] * C[1][3] * C[2][2] - C[0][2] * C[1][0] * C[2][3] + C[0][0] * C[1][2] * C[2][3]);
- dst->c[2][0] = d * (C[1][1] * C[2][3] * C[3][0] - C[1][3] * C[2][1] * C[3][0] + C[1][3] * C[2][0] * C[3][1] - C[1][0] * C[2][3] * C[3][1] - C[1][1] * C[2][0] * C[3][3] + C[1][0] * C[2][1] * C[3][3]);
- dst->c[2][1] = d * (C[0][3] * C[2][1] * C[3][0] - C[0][1] * C[2][3] * C[3][0] - C[0][3] * C[2][0] * C[3][1] + C[0][0] * C[2][3] * C[3][1] + C[0][1] * C[2][0] * C[3][3] - C[0][0] * C[2][1] * C[3][3]);
- dst->c[2][2] = d * (C[0][1] * C[1][3] * C[3][0] - C[0][3] * C[1][1] * C[3][0] + C[0][3] * C[1][0] * C[3][1] - C[0][0] * C[1][3] * C[3][1] - C[0][1] * C[1][0] * C[3][3] + C[0][0] * C[1][1] * C[3][3]);
- dst->c[2][3] = d * (C[0][3] * C[1][1] * C[2][0] - C[0][1] * C[1][3] * C[2][0] - C[0][3] * C[1][0] * C[2][1] + C[0][0] * C[1][3] * C[2][1] + C[0][1] * C[1][0] * C[2][3] - C[0][0] * C[1][1] * C[2][3]);
- dst->c[3][0] = d * (C[1][2] * C[2][1] * C[3][0] - C[1][1] * C[2][2] * C[3][0] - C[1][2] * C[2][0] * C[3][1] + C[1][0] * C[2][2] * C[3][1] + C[1][1] * C[2][0] * C[3][2] - C[1][0] * C[2][1] * C[3][2]);
- dst->c[3][1] = d * (C[0][1] * C[2][2] * C[3][0] - C[0][2] * C[2][1] * C[3][0] + C[0][2] * C[2][0] * C[3][1] - C[0][0] * C[2][2] * C[3][1] - C[0][1] * C[2][0] * C[3][2] + C[0][0] * C[2][1] * C[3][2]);
- dst->c[3][2] = d * (C[0][2] * C[1][1] * C[3][0] - C[0][1] * C[1][2] * C[3][0] - C[0][2] * C[1][0] * C[3][1] + C[0][0] * C[1][2] * C[3][1] + C[0][1] * C[1][0] * C[3][2] - C[0][0] * C[1][1] * C[3][2]);
- dst->c[3][3] = d * (C[0][1] * C[1][2] * C[2][0] - C[0][2] * C[1][1] * C[2][0] + C[0][2] * C[1][0] * C[2][1] - C[0][0] * C[1][2] * C[2][1] - C[0][1] * C[1][0] * C[2][2] + C[0][0] * C[1][1] * C[2][2]);
-
- return dst;
-}
-
-static inline struct vector3 *
-matrix44_gettrans(const union matrix44 *m, struct vector3 *trans)
-{
- // Getting translation is trivial
- trans->x = C[3][0];
- trans->y = C[3][1];
- trans->z = C[3][2];
-
- return trans;
-}
-
-static inline struct vector3 *
-matrix44_getscale(const union matrix44 *m, struct vector3 *scale)
-{
- // Scale is length of columns
- scale->x = sqrtf(C[0][0] * C[0][0] + C[0][1] * C[0][1] + C[0][2] * C[0][2]);
- scale->y = sqrtf(C[1][0] * C[1][0] + C[1][1] * C[1][1] + C[1][2] * C[1][2]);
- scale->z = sqrtf(C[2][0] * C[2][0] + C[2][1] * C[2][1] + C[2][2] * C[2][2]);
-
- return scale;
-}
-
-static inline void
-matrix44_decompose(const union matrix44 *m, struct vector3 *trans, struct vector3 *rot, struct vector3 *scale)
-{
- matrix44_gettrans(m, trans);
- matrix44_getscale(m, scale);
-
- if (scale->x == 0 || scale->y == 0 || scale->z == 0)
- {
- rot->x = 0;
- rot->y = 0;
- rot->z = 0;
- return;
- }
-
- // Detect negative scale with determinant and flip one arbitrary axis
- if (matrix44_determinant(m) < 0)
- scale->x = -scale->x;
-
- // Combined rotation matrix YXZ
- //
- // Cos[y]*Cos[z]+Sin[x]*Sin[y]*Sin[z] Cos[z]*Sin[x]*Sin[y]-Cos[y]*Sin[z] Cos[x]*Sin[y]
- // Cos[x]*Sin[z] Cos[x]*Cos[z] -Sin[x]
- // -Cos[z]*Sin[y]+Cos[y]*Sin[x]*Sin[z] Cos[y]*Cos[z]*Sin[x]+Sin[y]*Sin[z] Cos[x]*Cos[y]
-
- rot->x = asinf(-C[2][1] / scale->z);
-
- // Special case: Cos[x] == 0 (when Sin[x] is +/-1)
- float f = fabsf(C[2][1] / scale->z);
-
- if (f > 0.999f && f < 1.001f)
- {
- // Pin arbitrarily one of y or z to zero
- // Mathematical equivalent of gimbal lock
- rot->y = 0;
-
- // Now: Cos[x] = 0, Sin[x] = +/-1, Cos[y] = 1, Sin[y] = 0
- // => m[0][0] = Cos[z] and m[1][0] = Sin[z]
- rot->z = atan2f(-C[1][0] / scale->y, C[0][0] / scale->x);
- }
- else
- {
- // Standard case
- rot->y = atan2f(C[2][0] / scale->z, C[2][2] / scale->z);
- rot->z = atan2f(C[0][1] / scale->x, C[1][1] / scale->y);
- }
-}
-
-static inline float *
-matrix44_to33(const union matrix44 *m, float m33[9])
-{
- m33[0] = C[0][0];
- m33[1] = C[0][1];
- m33[2] = C[0][2];
- m33[3] = C[1][0];
- m33[4] = C[1][1];
- m33[5] = C[1][2];
- m33[6] = C[2][0];
- m33[7] = C[2][1];
- m33[8] = C[2][2];
-
- return m33;
-}
-
-#undef C
-
-// plane
-
-static inline struct plane *
-plane_init(struct plane *p, const struct vector3 *normal, float d)
-{
- p->normal = *normal;
- // normalize
- float invLen = 1.0f / vector3_length(normal);
- p->normal.x *= invLen;
- p->normal.y *= invLen;
- p->normal.z *= invLen;
- p->dist = d * invLen;
-
- return p;
-}
-
-static inline struct plane *
-plane_init_dot3(struct plane *p, const struct vector3 *v0, const struct vector3 *v1, const struct vector3 *v2)
-{
- struct vector3 a, b;
- vector3_vector(&a, v1, v0);
- vector3_vector(&b, v2, v0);
-
- vector3_cross(&p->normal, &a, &b);
- vector3_normalize(&p->normal);
- p->dist = -vector3_dot(&p->normal, v0);
-
- return p;
-}
-
-static inline float
-plane_dist(const struct plane *p, const struct vector3 *v)
-{
- float d = vector3_dot(&p->normal, v);
- return d + p->dist;
-}
-
-// Intersection
-
-static inline struct vector3 *
-intersection_raytriangle(const struct vector3 *rayOrig, const struct vector3 *rayDir,
- const struct vector3 *vert0, const struct vector3 *vert1, const struct vector3 *vert2,
- struct vector3 *intsPoint)
-{
- // Idea: Tomas Moeller and Ben Trumbore
- // in Fast, Minimum Storage Ray/Triangle Intersection
-
- // Find vectors for two edges sharing vert0
- struct vector3 edge1, edge2;
- vector3_vector(&edge1, vert1, vert0);
- vector3_vector(&edge2, vert2, vert0);
-
- // Begin calculating determinant - also used to calculate U parameter
- struct vector3 pvec;
- vector3_cross(&pvec, rayDir, &edge2);
-
- // If determinant is near zero, ray lies in plane of triangle
- float det = vector3_dot(&edge1, &pvec);
-
- // *** Culling branch ***
- /*if( det < FLT_EPSILON )
- return NULL;
-
- // Calculate distance from vert0 to ray origin
- struct vector3 tvec;
- vector3_vector(&tvec, rayOrig, &vert0);
-
- // Calculate U parameter and test bounds
- float u = vector3_dot(&tvec, &pvec);
- if (u < 0 || u > det )
- return NULL;
-
- // Prepare to test V parameter
- struct vector3 qvec;
- vector3_cross(&qvec, &tvec, &edge1);
-
- // Calculate V parameter and test bounds
- float v = vector3_dot(rayDir, &qvec);
- if (v < 0 || u + v > det )
- return NULL;
-
- // Calculate t, scale parameters, ray intersects triangle
- float t = vector3_dot(&edge2, &qvec ) / det;*/
-
- // *** Non-culling branch ***
- if (det > -FLT_EPSILON && det < FLT_EPSILON)
- return 0;
- float inv_det = 1.0f / det;
-
- // Calculate distance from vert0 to ray origin
- struct vector3 tvec;
- vector3_vector(&tvec, rayOrig, vert0);
-
- // Calculate U parameter and test bounds
- float u = vector3_dot(&tvec, &pvec) * inv_det;
- if (u < 0.0f || u > 1.0f)
- return 0;
-
- // Prepare to test V parameter
- struct vector3 qvec;
- vector3_cross(&qvec, &tvec, &edge1);
-
- // Calculate V parameter and test bounds
- float v = vector3_dot(rayDir, &qvec) * inv_det;
- if (v < 0.0f || u + v > 1.0f)
- return 0;
-
- // Calculate t, ray intersects triangle
- float t = vector3_dot(&edge2, &qvec) * inv_det;
-
- // Calculate intersection point and test ray length and direction
- intsPoint->x = rayOrig->x + rayDir->x * t;
- intsPoint->y = rayOrig->y + rayDir->y * t;
- intsPoint->z = rayOrig->z + rayDir->z * t;
-
- struct vector3 vec;
- vector3_vector(&vec, intsPoint, rayOrig);
- if (vector3_dot(&vec, rayDir) < 0 || vector3_length(&vec) > vector3_length(rayDir))
- return NULL;
-
- return intsPoint;
-}
-
-static inline float
-minf(float a, float b)
-{
- return a < b ? a : b;
-}
-
-static inline float
-maxf(float a, float b)
-{
- return a > b ? a : b;
-}
-
-static inline int
-intersection_rayAABB(const struct vector3 *rayOrig, const struct vector3 *rayDir,
- const struct vector3 *mins, const struct vector3 *maxs)
-{
- // SLAB based optimized ray/AABB intersection routine
- // Idea taken from http://ompf.org/ray/
-
- float l1 = (mins->x - rayOrig->x) / rayDir->x;
- float l2 = (maxs->x - rayOrig->x) / rayDir->x;
- float lmin = minf(l1, l2);
- float lmax = maxf(l1, l2);
-
- l1 = (mins->y - rayOrig->y) / rayDir->y;
- l2 = (maxs->y - rayOrig->y) / rayDir->y;
- lmin = maxf(minf(l1, l2), lmin);
- lmax = minf(maxf(l1, l2), lmax);
-
- l1 = (mins->z - rayOrig->z) / rayDir->z;
- l2 = (maxs->z - rayOrig->z) / rayDir->z;
- lmin = maxf(minf(l1, l2), lmin);
- lmax = minf(maxf(l1, l2), lmax);
-
- if ((lmax >= 0.0f) & (lmax >= lmin))
- {
- // Consider length
- const struct vector3 rayDest = {rayOrig->x + rayDir->x, rayOrig->y + rayDir->y, rayOrig->z + rayDir->z};
- const struct vector3 rayMins = {minf(rayDest.x, rayOrig->x), minf(rayDest.y, rayOrig->y), minf(rayDest.z, rayOrig->z)};
- const struct vector3 rayMaxs = {maxf(rayDest.x, rayOrig->x), maxf(rayDest.y, rayOrig->y), maxf(rayDest.z, rayOrig->z)};
- return (rayMins.x < maxs->x) && (rayMaxs.x > mins->x) &&
- (rayMins.y < maxs->y) && (rayMaxs.y > mins->y) &&
- (rayMins.z < maxs->z) && (rayMaxs.z > mins->z);
- }
- else
- {
- return 0;
- }
-}
-
-static inline float
-vector3_distAABB(const struct vector3 *pos, const struct vector3 *mins, const struct vector3 *maxs)
-{
- struct vector3 center;
- struct vector3 extent;
- center.x = (mins->x + maxs->x) * 0.5f;
- center.y = (mins->y + maxs->y) * 0.5f;
- center.z = (mins->z + maxs->z) * 0.5f;
-
- extent.x = (maxs->x - mins->x) * 0.5f;
- extent.y = (maxs->y - mins->y) * 0.5f;
- extent.z = (maxs->z - mins->z) * 0.5f;
-
- struct vector3 nearestVec;
- nearestVec.x = maxf(0, fabsf(pos->x - center.x) - extent.x);
- nearestVec.y = maxf(0, fabsf(pos->y - center.y) - extent.y);
- nearestVec.z = maxf(0, fabsf(pos->z - center.z) - extent.z);
-
- return vector3_length(&nearestVec);
-}
-
-#endif
diff --git a/framework/lualib-src/math3d/.gitignore b/framework/lualib-src/math3d/.gitignore
new file mode 100755
index 0000000..a74ece7
--- /dev/null
+++ b/framework/lualib-src/math3d/.gitignore
@@ -0,0 +1,2 @@
+o
+*.dll
diff --git a/framework/lualib-src/math3d/Makefile b/framework/lualib-src/math3d/Makefile
new file mode 100755
index 0000000..3a40056
--- /dev/null
+++ b/framework/lualib-src/math3d/Makefile
@@ -0,0 +1,43 @@
+SKYNET_ROOT ?= ../../skynet
+include $(SKYNET_ROOT)/platform.mk
+
+LUALIB ?= $(SKYNET_ROOT)/3rd/lua/
+LUAINC ?= $(SKYNET_ROOT)/3rd/lua/
+GLM_INC = -I ../../3rd/glm
+ODIR = o
+OUTPUT= ../../luaclib/
+
+PLAT ?= none
+ifeq ($(PLAT), macosx)
+ CFLAGS = -g -O2 -dynamiclib -Wl,-undefined,dynamic_lookup -std=gnu99
+else
+ifeq ($(PLAT), linux)
+ CFLAGS = -g -O2 -shared -fPIC -std=gnu99
+endif
+endif
+
+all : $(OUTPUT)math3d.so
+
+$(ODIR)/linalg.o : linalg.c | $(ODIR)
+ $(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
+
+$(ODIR)/math3d.o : math3d.c | $(ODIR)
+ $(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
+
+$(ODIR)/mathfunc.o : mathfunc.cpp | $(ODIR)
+ $(CXX) -c $(CFLAGS) -Wno-char-subscripts -o $@ $^ $(GLM_INC)
+
+$(ODIR)/mathadapter.o : mathadapter.c | $(ODIR)
+ $(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
+
+$(ODIR)/testadapter.o : testadapter.c | $(ODIR)
+ $(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
+
+$(OUTPUT)math3d.so : $(ODIR)/linalg.o $(ODIR)/math3d.o $(ODIR)/mathfunc.o $(ODIR)/mathadapter.o $(ODIR)/testadapter.o
+ $(CXX) --shared $(CFLAGS) -o $@ $^ -lstdc++ $(LUALIB)
+
+$(ODIR) :
+ mkdir -p $@
+
+clean :
+ rm -rf $(ODIR) *.so
diff --git a/framework/lualib-src/math3d/fastmath.h b/framework/lualib-src/math3d/fastmath.h
new file mode 100755
index 0000000..c13d978
--- /dev/null
+++ b/framework/lualib-src/math3d/fastmath.h
@@ -0,0 +1,23 @@
+#ifndef math_fastcall_h
+#define math_fastcall_h
+
+#include
+#include "linalg.h"
+#include "refstack.h"
+
+typedef int (*MFunction)(lua_State *L, struct lastack *LS, struct ref_stack *RS);
+
+#define FASTMATH(f)\
+int m_##f(lua_State *L, struct lastack *LS_, struct ref_stack *RS_) {\
+ struct ref_stack tmpRS; \
+ struct lastack *LS;\
+ struct ref_stack *RS;\
+ if (L == NULL) {\
+ L = RS_->L; LS=LS_; RS=RS_; (void)LS; (void)RS;\
+ } else {\
+ LS = getLS(L, 1); refstack_init(&tmpRS, L); RS = &tmpRS;\
+ }
+
+#define MFUNCTION(f) #f, (lua_CFunction)( m_##f )
+
+#endif
diff --git a/framework/lualib-src/math3d/linalg.c b/framework/lualib-src/math3d/linalg.c
new file mode 100755
index 0000000..e68dec2
--- /dev/null
+++ b/framework/lualib-src/math3d/linalg.c
@@ -0,0 +1,808 @@
+#include
+#include
+#include
+#include
+#include
+#include "linalg.h"
+
+#define MINCAP 128
+
+#define VECTOR4 4
+#define MATRIX 16
+
+// Constant: version should be 0, id is the constant id, persistent should be 1
+
+static float c_ident_vec[4] = { 0,0,0,1 };
+static float c_ident_mat[16] = {
+ 1,0,0,0,
+ 0,1,0,0,
+ 0,0,1,0,
+ 0,0,0,1,
+};
+
+static float c_ident_quat[4] = {
+ 0, 0, 0, 1,
+};
+
+struct constant {
+ float * ptr;
+ int size;
+};
+
+static struct constant c_constant_table[LINEAR_TYPE_COUNT] = {
+ { c_ident_mat, MATRIX },
+ { c_ident_vec, VECTOR4 },
+ { c_ident_quat, VECTOR4 },
+};
+
+struct stackid_ {
+ uint32_t version:24;
+ uint32_t id:24;
+ uint32_t type : LINEAR_TYPE_BITS_NUM; // 0:matrix 1:vector4 2:float 3:quaternion 4:euler
+ uint32_t persistent:1; // 0: persisent 1: temp
+};
+
+union stackid {
+ struct stackid_ s;
+ int64_t i;
+};
+
+int64_t
+lastack_constant(int cons) {
+ if (cons < 0 || cons >= LINEAR_TYPE_COUNT)
+ return 0;
+ union stackid sid;
+ sid.s.version = 0;
+ sid.s.id = cons;
+ sid.s.persistent = 1;
+ sid.s.type = cons;
+
+ return sid.i;
+}
+
+struct lastack {
+ int temp_vector_cap;
+ int temp_vector_top;
+ int temp_matrix_cap;
+ int temp_matrix_top;
+ int version;
+ int stack_cap;
+ int stack_top;
+ float * temp_vec;
+ float * temp_mat;
+ struct blob * per_vec;
+ struct blob * per_mat;
+ struct oldpage *old;
+ union stackid *stack;
+ size_t oldpage_size;
+};
+
+#define TAG_FREE 0
+#define TAG_USED 1
+#define TAG_WILLFREE 2
+
+struct slot {
+ uint32_t id : 30;
+ uint32_t tag : 2;
+};
+
+struct oldpage {
+ struct oldpage *next;
+ void *page;
+};
+
+struct blob {
+ int size;
+ int cap;
+ int freeslot; // free slot list
+ int freelist; // will free
+ char * buffer;
+ struct slot *s;
+ struct oldpage *old;
+ size_t oldpage_size;
+};
+
+static inline void
+init_blob_slots(struct blob * B, int slot_beg, int slot_end) {
+ int i;
+ for (i = slot_beg; i < slot_end; ++i) {
+ B->s[i].tag = TAG_FREE;
+ B->s[i].id = i + 2;
+ }
+
+ B->s[slot_end - 1].id = 0;
+ B->freeslot = slot_beg + 1;
+}
+
+static struct blob *
+blob_new(int size, int cap) {
+ struct blob * B = malloc(sizeof(*B));
+ B->size = size;
+ B->cap = cap;
+ B->freelist = 0; // empty list
+ B->buffer = malloc(size * cap);
+ B->s = malloc(cap * sizeof(*B->s));
+ init_blob_slots(B, 0, cap);
+ B->old = NULL;
+ B->oldpage_size = 0;
+ return B;
+}
+
+static size_t
+blob_size(struct blob *B) {
+ return sizeof(*B) + (B->size + sizeof(*B->s)) * B->cap + B->oldpage_size;
+}
+
+static void
+free_oldpage(struct oldpage *p) {
+ while (p) {
+ struct oldpage *next = p->next;
+ free(p->page);
+ free(p);
+ p = next;
+ }
+}
+
+#define SLOT_INDEX(idx) ((idx)-1)
+#define SLOT_EMPTY(idx) ((idx)==0)
+
+static int
+blob_alloc(struct blob *B, int version) {
+ if (SLOT_EMPTY(B->freeslot)) {
+ struct oldpage * p = malloc(sizeof(*p));
+ p->next = B->old;
+ p->page = B->buffer;
+ B->old = p;
+
+ int cap = B->cap;
+ B->oldpage_size += sizeof(*p) + B->size * cap;
+
+ B->cap *= 2;
+ B->buffer = malloc(B->size * B->cap);
+ memcpy(B->buffer, p->page, B->size * cap);
+ B->s = realloc(B->s, B->cap * sizeof(*B->s));
+ static int alloc_count = 0;
+ alloc_count ++;
+ init_blob_slots(B, cap, B->cap);
+ }
+ int ret = SLOT_INDEX(B->freeslot);
+ struct slot *s = &B->s[ret];
+ B->freeslot = s->id; // next free slot
+ s->tag = TAG_USED;
+ s->id = version;
+ return ret;
+}
+
+static void *
+blob_address(struct blob *B, int index, int version) {
+ struct slot *s = &B->s[index];
+ if (s->tag != TAG_USED || s->id != version)
+ return NULL;
+ return B->buffer + index * B->size;
+}
+
+static void
+blob_dealloc(struct blob *B, int index, int version) {
+ struct slot *s = &B->s[index];
+ if (s->tag != TAG_USED || s->id != version)
+ return;
+ s->id = B->freelist;
+ s->tag = TAG_WILLFREE;
+ B->freelist = index + 1;
+}
+
+static void
+blob_flush(struct blob *B) {
+ int slot = B->freelist;
+ while (slot) {
+ struct slot *s = &B->s[SLOT_INDEX(slot)];
+ s->tag = TAG_FREE;
+ if (SLOT_EMPTY(s->id)) {
+ s->id = B->freeslot;
+ B->freeslot = B->freelist;
+ B->freelist = 0;
+ break;
+ }
+ slot = s->id;
+ }
+ free_oldpage(B->old);
+ B->old = NULL;
+ B->oldpage_size = 0;
+}
+
+static void
+blob_delete(struct blob *B) {
+ if (B) {
+ free(B->buffer);
+ free(B->s);
+ free_oldpage(B->old);
+ free(B);
+ }
+}
+
+static void
+print_list(struct blob *B, const char * h, int list, int tag) {
+ printf("%s ", h);
+ while (!SLOT_EMPTY(list)) {
+ int index = SLOT_INDEX(list);
+ struct slot *s = &B->s[index];
+ if (s->tag == tag) {
+ printf("%d,", SLOT_INDEX(list));
+ } else {
+ printf("%d [ERROR]", SLOT_INDEX(list));
+ break;
+ }
+ list = s->id;
+ }
+ printf("\n");
+}
+
+static void
+blob_print(struct blob *B) {
+ int i;
+ printf("USED: ");
+ for (i=0;icap;i++) {
+ if (B->s[i].tag == TAG_USED) {
+ printf("%d,", i);
+ }
+ }
+ printf("\n");
+ print_list(B, "FREE :", B->freeslot, TAG_FREE);
+ print_list(B, "WILLFREE :", B->freelist, TAG_WILLFREE);
+}
+
+#if 0
+int
+blob_test_main() {
+ struct blob *B = blob_new(4, 10);
+ int a = blob_alloc(B,1);
+ int b = blob_alloc(B,1);
+ int c = blob_alloc(B,1);
+ blob_print(B);
+ blob_dealloc(B, a, 1);
+ blob_print(B);
+ blob_flush(B);
+ blob_print(B);
+
+
+ return 0;
+}
+#endif
+
+struct lastack *
+lastack_new() {
+ struct lastack * LS = malloc(sizeof(*LS));
+ LS->temp_vector_cap = MINCAP;
+ LS->temp_vector_top = 0;
+ LS->temp_matrix_cap = MINCAP;
+ LS->temp_matrix_top = 0;
+ LS->version = 1; // base 1
+ LS->stack_cap = MINCAP;
+ LS->stack_top = 0;
+ LS->temp_vec = malloc(LS->temp_vector_cap * VECTOR4 * sizeof(float));
+ LS->temp_mat = malloc(LS->temp_matrix_cap * MATRIX * sizeof(float));
+ LS->per_vec = blob_new(VECTOR4 * sizeof(float), MINCAP);
+ LS->per_mat = blob_new(MATRIX * sizeof(float), MINCAP);
+ LS->old = NULL;
+ LS->stack = malloc(LS->stack_cap * sizeof(*LS->stack));
+ LS->oldpage_size = 0;
+ return LS;
+}
+
+size_t
+lastack_size(struct lastack *LS) {
+ return sizeof(*LS)
+ + LS->temp_vector_cap * VECTOR4 * sizeof(float)
+ + LS->temp_matrix_cap * MATRIX * sizeof(float)
+ + LS->stack_cap * sizeof(*LS->stack)
+ + blob_size(LS->per_vec)
+ + blob_size(LS->per_mat);
+}
+
+void
+lastack_delete(struct lastack *LS) {
+ if (LS == NULL)
+ return;
+ free(LS->temp_vec);
+ free(LS->temp_mat);
+ blob_delete(LS->per_vec);
+ blob_delete(LS->per_mat);
+ free(LS->stack);
+ free_oldpage(LS->old);
+ free(LS);
+}
+
+static inline void
+push_id(struct lastack *LS, union stackid id) {
+ if (LS->stack_top >= LS->stack_cap) {
+ LS->stack = realloc(LS->stack, (LS->stack_cap *= 2) * sizeof(*LS->stack));
+ }
+ LS->stack[LS->stack_top++] = id;
+}
+
+static void *
+new_page(struct lastack *LS, void *page, size_t page_size) {
+ struct oldpage * p = malloc(sizeof(*p));
+ p->next = LS->old;
+ p->page = page;
+ LS->old = p;
+ LS->oldpage_size += page_size + sizeof(*p);
+ return page;
+}
+
+int
+lastack_typesize(int type) {
+ const int sizes[LINEAR_TYPE_COUNT] = { 16, 4, 4 };
+// assert(LINEAR_TYPE_MAT <= type && type < LINEAR_TYPE_COUNT);
+ return sizes[type];
+}
+
+const char *
+lastack_typename(int t) {
+ static const char * type_names[] = {
+ "mat",
+ "v4",
+ "quat",
+ };
+ if (t < 0 || t >= sizeof(type_names)/sizeof(type_names[0]))
+ return "unknown";
+ return type_names[t];
+}
+
+
+static float *
+check_matrix_pool(struct lastack *LS) {
+ if (LS->temp_matrix_top >= LS->temp_matrix_cap) {
+ size_t sz = LS->temp_matrix_cap * sizeof(float) * MATRIX;
+ void * p = new_page(LS, LS->temp_mat, sz);
+ LS->temp_mat = malloc(sz * 2);
+ memcpy(LS->temp_mat, p, sz);
+ LS->temp_matrix_cap *= 2;
+ }
+ return LS->temp_mat + LS->temp_matrix_top * MATRIX;
+}
+
+void
+lastack_pushmatrix(struct lastack *LS, const float *mat) {
+ float * pmat = check_matrix_pool(LS);
+ memcpy(pmat, mat, sizeof(float) * MATRIX);
+ union stackid sid;
+ sid.s.type = LINEAR_TYPE_MAT;
+ sid.s.persistent = 0;
+ sid.s.version = LS->version;
+ sid.s.id = LS->temp_matrix_top;
+ push_id(LS, sid);
+ ++ LS->temp_matrix_top;
+}
+
+void
+lastack_pushsrt(struct lastack *LS, const float *s, const float *r, const float *t) {
+#define NOTIDENTITY (~0)
+ float * mat = check_matrix_pool(LS);
+ uint32_t * mark = (uint32_t *)&mat[3*4];
+ // scale
+ float *scale = &mat[0];
+ if (s == NULL) {
+ scale[0] = 1;
+ scale[1] = 1;
+ scale[2] = 1;
+ scale[3] = 0;
+ mark[0] = 0;
+ } else {
+ float sx = s[0];
+ float sy = s[1];
+ float sz = s[2];
+ scale[0] = sx;
+ scale[1] = sy;
+ scale[2] = sz;
+ scale[3] = 0;
+ if (sx == 1 && sy == 1 && sz == 1) {
+ mark[0] = NOTIDENTITY;
+ }
+ }
+ // rotation
+ float *rotation = &mat[4*1];
+ if (r == NULL || (r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1)) {
+ rotation[0] = 0;
+ rotation[1] = 0;
+ rotation[2] = 0;
+ rotation[3] = 1;
+ mark[1] = 0;
+ } else {
+ rotation[0] = r[0];
+ rotation[1] = r[1];
+ rotation[2] = r[2];
+ rotation[3] = r[3];
+ mark[1] = NOTIDENTITY;
+ }
+ // translate
+ float *translate = &mat[4*2];
+ if (t == NULL || (t[0] == 0 && t[1] == 0 && t[2] == 0)) {
+ translate[0] = 0;
+ translate[1] = 0;
+ translate[2] = 0;
+ translate[3] = 1;
+ mark[2] = 0;
+ } else {
+ translate[0] = t[0];
+ translate[1] = t[1];
+ translate[2] = t[2];
+ translate[3] = 1;
+ mark[2] = NOTIDENTITY;
+ }
+ // mark identity
+ if (mark[0] == 0 && mark[1] == 0 && mark[2] == 0) {
+ mark[3] = 0;
+ } else {
+ mark[3] = NOTIDENTITY;
+ }
+ union stackid sid;
+ sid.s.type = LINEAR_TYPE_MAT;
+ sid.s.persistent = 0;
+ sid.s.version = LS->version;
+ sid.s.id = LS->temp_matrix_top;
+ push_id(LS, sid);
+ ++ LS->temp_matrix_top;
+}
+
+void
+lastack_pushobject(struct lastack *LS, const float *v, int type) {
+ if (type == LINEAR_TYPE_MAT) {
+ lastack_pushmatrix(LS, v);
+ return;
+ }
+ assert(type >= LINEAR_TYPE_VEC4 && type <= LINEAR_TYPE_QUAT);
+ const int size = lastack_typesize(type);
+ if (LS->temp_vector_top >= LS->temp_vector_cap) {
+ size_t sz = LS->temp_vector_cap * sizeof(float) * VECTOR4;
+ void * p = new_page(LS, LS->temp_vec, sz);
+ LS->temp_vec = malloc(sz * 2);
+ memcpy(LS->temp_vec, p, sz);
+ LS->temp_vector_cap *= 2;
+ }
+ memcpy(LS->temp_vec + LS->temp_vector_top * VECTOR4, v, sizeof(float) * size);
+ union stackid sid;
+ sid.s.type = type;
+ sid.s.persistent = 0;
+ sid.s.version = LS->version;
+ sid.s.id = LS->temp_vector_top;
+ push_id(LS, sid);
+ ++ LS->temp_vector_top;
+}
+
+void
+lastack_pushvec4(struct lastack *LS, const float *vec4) {
+ lastack_pushobject(LS, vec4, LINEAR_TYPE_VEC4);
+}
+
+void
+lastack_pushquat(struct lastack *LS, const float *v) {
+ lastack_pushobject(LS, v, LINEAR_TYPE_QUAT);
+}
+
+const float *
+lastack_value(struct lastack *LS, int64_t ref, int *type) {
+ union stackid sid;
+ sid.i = ref;
+ int id = sid.s.id;
+ int ver = sid.s.version;
+ void * address = NULL;
+ if (type)
+ *type = sid.s.type;
+ if (sid.s.persistent) {
+ if (sid.s.version == 0) {
+ // constant
+ int id = sid.s.id;
+ if (id < 0 || id >= LINEAR_TYPE_COUNT)
+ return NULL;
+ struct constant * c = &c_constant_table[id];
+ return c->ptr;
+ }
+ if (lastack_typesize(sid.s.type) == MATRIX) {
+ address = blob_address( LS->per_mat , id, ver);
+ } else {
+ address = blob_address( LS->per_vec , id, ver);
+ }
+ return address;
+ } else {
+ if (ver != LS->version) {
+ // version expired
+ return NULL;
+ }
+ if (lastack_typesize(sid.s.type) == MATRIX) {
+ if (id >= LS->temp_matrix_top) {
+ return NULL;
+ }
+ return LS->temp_mat + id * MATRIX;
+ } else {
+ if (id >= LS->temp_vector_top) {
+ return NULL;
+ }
+ return LS->temp_vec + id * VECTOR4;
+ }
+ }
+}
+
+int
+lastack_pushref(struct lastack *LS, int64_t ref) {
+ union stackid id;
+ id.i = ref;
+ // check alive
+ const void *address = lastack_value(LS, id.i, NULL);
+ if (address == NULL)
+ return 1;
+ push_id(LS, id);
+ return 0;
+}
+
+void
+lastack_unmark(struct lastack *LS, int64_t markid) {
+ union stackid id;
+ id.i = markid;
+ if (id.s.persistent && id.s.version != 0) {
+ if (lastack_typesize(id.s.type) != MATRIX) {
+ blob_dealloc(LS->per_vec, id.s.id, id.s.version);
+ } else {
+ blob_dealloc(LS->per_mat, id.s.id, id.s.version);
+ }
+ }
+}
+
+int
+lastack_isconstant(int64_t markid) {
+ union stackid id;
+ id.i = markid;
+ return (id.s.persistent && id.s.version == 0);
+}
+
+int64_t
+lastack_mark(struct lastack *LS, int64_t tempid) {
+ if (lastack_isconstant(tempid))
+ return tempid;
+ int t;
+ const float *address = lastack_value(LS, tempid, &t);
+ if (address == NULL) {
+ //printf("--- mark address = null ---");
+ return 0;
+ }
+ int id;
+ union stackid sid;
+ sid.s.version = LS->version;
+ sid.s.type = t;
+ if (lastack_typesize(t) != MATRIX) {
+ id = blob_alloc(LS->per_vec, LS->version);
+ void * dest = blob_address(LS->per_vec, id, LS->version);
+ memcpy(dest, address, sizeof(float) * VECTOR4);
+ } else {
+ id = blob_alloc(LS->per_mat, LS->version);
+ void * dest = blob_address(LS->per_mat, id, LS->version);
+ memcpy(dest, address, sizeof(float) * MATRIX);
+ }
+ sid.s.id = id;
+ if (sid.s.id != id) {
+ //printf(" --- s.id(%d) != id(%d) --- \n ",sid.s.id,id);
+ return 0;
+ }
+ sid.s.persistent = 1;
+ return sid.i;
+}
+
+int
+lastack_marked(int64_t id, int *type) {
+ union stackid sid;
+ sid.i = id;
+ if (type) {
+ *type = sid.s.type;
+ }
+ return sid.s.persistent;
+}
+
+int
+lastack_sametype(int64_t id1, int64_t id2) {
+ union stackid sid1,sid2;
+ sid1.i = id1;
+ sid2.i = id2;
+ return sid1.s.type == sid2.s.type;
+}
+
+int64_t
+lastack_pop(struct lastack *LS) {
+ if (LS->stack_top <= 0)
+ return 0;
+ union stackid sid = LS->stack[--LS->stack_top];
+ return sid.i;
+}
+
+int64_t
+lastack_top(struct lastack *LS) {
+ if (LS->stack_top <= 0)
+ return 0;
+ union stackid sid = LS->stack[LS->stack_top-1];
+ return sid.i;
+}
+
+int64_t
+lastack_dup(struct lastack *LS, int index) {
+ if (LS->stack_top < index || index <= 0)
+ return 0;
+ union stackid sid = LS->stack[LS->stack_top-index];
+ push_id(LS, sid);
+ return sid.i;
+}
+
+int64_t
+lastack_swap(struct lastack *LS) {
+ if (LS->stack_top <= 1)
+ return 0;
+ union stackid top = LS->stack[LS->stack_top-1];
+ union stackid newtop = LS->stack[LS->stack_top-2];
+ LS->stack[LS->stack_top-2] = top;
+ LS->stack[LS->stack_top-1] = newtop;
+ return newtop.i;
+}
+
+void
+lastack_reset(struct lastack *LS) {
+ union stackid v;
+ v.s.version = LS->version + 1;
+ if (v.s.version == 0)
+ ++ v.s.version;
+ LS->version = v.s.version;
+ LS->stack_top = 0;
+ free_oldpage(LS->old);
+ LS->old = NULL;
+ LS->oldpage_size = 0;
+ blob_flush(LS->per_vec);
+ blob_flush(LS->per_mat);
+ LS->temp_vector_top = 0;
+ LS->temp_matrix_top = 0;
+}
+
+static void
+print_float(const float *address, int n) {
+ int i;
+ for (i=0;iversion);
+ printf("stack %d/%d:\n", LS->stack_top, LS->stack_cap);
+ int i;
+ for (i=0;istack_top;i++) {
+ union stackid id = LS->stack[i];
+ int type;
+ const float *address = lastack_value(LS, id.i, &type);
+ printf("\t[%d]", i);
+ if (id.s.persistent) {
+ printf("version = %d ", id.s.version);
+ }
+ print_object(address, id.s.id, type);
+ printf("\n");
+ }
+ printf("Persistent Vector ");
+ blob_print(LS->per_vec);
+ printf("Persistent Matrix ");
+ blob_print(LS->per_mat);
+}
+
+int
+lastack_gettop(struct lastack *LS) {
+ return LS->stack_top;
+}
+
+void
+lastack_dump(struct lastack *LS, int from) {
+ if (from < 0) {
+ from = LS->stack_top + from;
+ if (from < 0)
+ from = 0;
+ }
+ int i;
+ for (i=LS->stack_top-1;i>=from;i--) {
+ union stackid id = LS->stack[i];
+ int type;
+ const float *address = lastack_value(LS, id.i, &type);
+ print_object(address, id.s.id, type);
+ }
+ if (from > 0) {
+ for (i=0;i
+#include
+
+enum LinearType {
+ LINEAR_TYPE_NONE = -1,
+ LINEAR_TYPE_MAT = 0,
+ LINEAR_TYPE_VEC4,
+ LINEAR_TYPE_QUAT,
+ LINEAR_TYPE_COUNT,
+};
+
+#define LINEAR_TYPE_BITS_NUM 3
+
+struct lastack;
+
+int64_t lastack_constant(int cons);
+int lastack_isconstant(int64_t id);
+int lastack_marked(int64_t id, int *type);
+int lastack_sametype(int64_t id1, int64_t id2);
+char * lastack_idstring(int64_t id, char tmp[64]); // for debug
+int lastack_typesize(int type);
+const char * lastack_typename(int type);
+
+struct lastack * lastack_new();
+void lastack_delete(struct lastack *LS);
+void lastack_pushobject(struct lastack *LS, const float *v, int type);
+void lastack_pushvec4(struct lastack *LS, const float *v);
+void lastack_pushquat(struct lastack *LS, const float *v);
+void lastack_pushmatrix(struct lastack *LS, const float *mat);
+void lastack_pushsrt(struct lastack *LS, const float *s, const float *r, const float *t);
+const float * lastack_value(struct lastack *LS, int64_t id, int *type);
+int lastack_pushref(struct lastack *LS, int64_t id);
+int64_t lastack_mark(struct lastack *LS, int64_t tempid);
+void lastack_unmark(struct lastack *LS, int64_t markid);
+int64_t lastack_pop(struct lastack *LS);
+int64_t lastack_top(struct lastack *LS);
+int64_t lastack_dup(struct lastack *LS, int index);
+int64_t lastack_swap(struct lastack *LS);
+void lastack_reset(struct lastack *LS);
+void lastack_print(struct lastack *LS); // for debug, dump all stack
+int lastack_gettop(struct lastack *LS); // for debug, get stack length
+void lastack_dump(struct lastack *LS, int from); // for debug, dump top values
+int lastack_type(struct lastack *LS, int64_t id);
+size_t lastack_size(struct lastack *LS);
+
+static inline int lastack_is_vec_type(int type) {
+ return (type == LINEAR_TYPE_VEC4) ? 1 : 0;
+}
+
+#endif
diff --git a/framework/lualib-src/math3d/math3d.c b/framework/lualib-src/math3d/math3d.c
new file mode 100755
index 0000000..6570b8c
--- /dev/null
+++ b/framework/lualib-src/math3d/math3d.c
@@ -0,0 +1,1344 @@
+#define LUA_LIB
+
+#include
+#include
+#include
+#include
+
+#ifndef _MSC_VER
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+#endif // !_MSC_VER
+
+#ifndef lua_newuserdata
+// lua_newuserdata is a macro in Lua 5.4
+#define lua_newuserdatauv(L, sz, n) lua_newuserdata(L,sz)
+#endif
+
+#include "string.h"
+
+#include "linalg.h"
+#include "math3d.h"
+#include "math3dfunc.h"
+
+#define MAT_PERSPECTIVE 0
+#define MAT_ORTHO 1
+
+static int g_default_homogeneous_depth = 0;
+
+int
+math3d_homogeneous_depth() {
+ return g_default_homogeneous_depth;
+}
+
+static inline void *
+STACKID(int64_t id) {
+ return (void *)id;
+}
+
+static inline void *
+REFID(struct refobject *R) {
+ return STACKID(R->id);
+}
+
+static inline int64_t
+LUAID(lua_State *L, int index) {
+ luaL_checktype(L, index, LUA_TLIGHTUSERDATA);
+ void * ud = lua_touserdata(L, index);
+ return (int64_t)ud;
+}
+
+static inline struct lastack *
+GETLS(lua_State *L) {
+ return (struct lastack *)lua_touserdata(L, lua_upvalueindex(1));
+}
+
+static void
+finalize(lua_State *L, lua_CFunction gc) {
+ lua_createtable(L, 0, 1);
+ lua_pushcfunction(L, gc);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+}
+
+static int
+boxstack_gc(lua_State *L) {
+ struct boxstack *bs = lua_touserdata(L, 1);
+ if (bs->LS) {
+ lastack_delete(bs->LS);
+ bs->LS = NULL;
+ }
+ return 0;
+}
+
+static int64_t
+get_id(lua_State *L, int index, int ltype) {
+ if (ltype == LUA_TLIGHTUSERDATA) {
+ return (int64_t)lua_touserdata(L, index);
+ } else if (ltype == LUA_TUSERDATA) {
+ if (lua_rawlen(L, index) != sizeof(struct refobject)) {
+ luaL_error(L, "Invalid ref userdata");
+ }
+ struct refobject * ref = lua_touserdata(L, index);
+ return ref->id;
+ }
+ return luaL_argerror(L, index, "Need userdata");
+}
+
+static int
+lref(lua_State *L) {
+ lua_settop(L, 1);
+ struct refobject * R = lua_newuserdatauv(L, sizeof(struct refobject), 0);
+ if (lua_isnil(L, 1)) {
+ R->id = 0;
+ } else {
+ int64_t id = get_id(L, 1, lua_type(L, 1));
+ R->id = lastack_mark(GETLS(L), id);
+ }
+ lua_pushvalue(L, lua_upvalueindex(2));
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int64_t
+assign_id(lua_State *L, struct lastack *LS, int index, int mtype, int ltype) {
+ switch (ltype) {
+ case LUA_TNIL:
+ case LUA_TNONE:
+ // identity matrix
+ return lastack_constant(mtype);
+ case LUA_TUSERDATA:
+ case LUA_TLIGHTUSERDATA: {
+ int64_t id = get_id(L, index, ltype);
+ int type;
+ const float * v = lastack_value(LS, id, &type);
+ if (type != mtype && v) {
+ if (mtype == LINEAR_TYPE_MAT && type == LINEAR_TYPE_QUAT) {
+ math3d_quat_to_matrix(LS, v);
+ id = lastack_pop(LS);
+ } else if (mtype == LINEAR_TYPE_QUAT && type == LINEAR_TYPE_MAT) {
+ math3d_matrix_to_quat(LS, v);
+ id = lastack_pop(LS);
+ } else {
+ return luaL_error(L, "%s type mismatch %s", lastack_typename(mtype), lastack_typename(type));
+ }
+ }
+ return lastack_mark(LS, id); }
+ default:
+ return luaL_error(L, "Invalid type %s for %s ref", lua_typename(L, ltype), lastack_typename(mtype));
+ }
+}
+
+static void
+unpack_numbers(lua_State *L, int index, float *v, int n) {
+ int i;
+ for (i=0;iid;
+ switch(key[0]) {
+ case 'i': // value id
+ R->id = lastack_mark(LS, get_id(L, 3, lua_type(L, 3)));
+ break;
+ case 'v': // should be vector
+ R->id = assign_vector(L, LS, 3);
+ break;
+ case 'q': // should be quat
+ R->id = assign_quat(L, LS, 3);
+ break;
+ case 'm': // should be matrix
+ R->id = assign_matrix(L, LS, 3);
+ break;
+ case 's':
+ R->id = assign_scale(L, LS, 3, oid);
+ break;
+ case 'r':
+ R->id = assign_rot(L, LS, 3, oid);
+ break;
+ case 't':
+ R->id = assign_trans(L, LS, 3, oid);
+ break;
+ default:
+ return luaL_error(L, "Invalid set key %s with ref object", key);
+ }
+ // we must unmark old id after assign, because 'v.i = v'
+ lastack_unmark(LS, oid);
+ return 0;
+}
+
+static void
+to_table(lua_State *L, struct lastack *LS, int64_t id) {
+ int type;
+ const float * v = lastack_value(LS, id, &type);
+ if (v == NULL) {
+ lua_pushnil(L);
+ return;
+ }
+ int n = lastack_typesize(type);
+ int i;
+ lua_createtable(L, n, 1);
+ for (i=0;iid, NULL)));
+ break;
+ case 'v':
+ to_table(L, LS, R->id);
+ break;
+ case 's':
+ case 'r':
+ case 't': {
+ int type;
+ const float *m = lastack_value(LS, R->id, &type);
+ if (m == NULL || type != LINEAR_TYPE_MAT)
+ return luaL_error(L, "Not a matrix");
+ lua_pushlightuserdata(L, STACKID(extract_srt(LS, m ,key[0])));
+ break; }
+ default:
+ return luaL_error(L, "Invalid get key %s with ref object", key);
+ }
+ return 1;
+}
+
+static int
+index_object(lua_State *L, struct lastack *LS, int64_t id, int idx) {
+ int type;
+ const float * v = lastack_value(LS, id, &type);
+ if (v == NULL) {
+ return luaL_error(L, "Invalid ref object");
+ }
+ if (idx < 1 || idx > 4) {
+ return luaL_error(L, "Invalid index %d", idx);
+ }
+ --idx;
+ switch (type) {
+ case LINEAR_TYPE_MAT:
+ lastack_pushvec4(LS, &v[idx*4]);
+ lua_pushlightuserdata(L, STACKID(lastack_pop(LS)));
+ break;
+ case LINEAR_TYPE_VEC4:
+ lua_pushnumber(L, v[idx]);
+ break;
+ case LINEAR_TYPE_QUAT:
+ lua_pushnumber(L, v[idx]);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int
+ref_get_number(lua_State *L) {
+ struct refobject *R = lua_touserdata(L, 1);
+ struct lastack * LS = GETLS(L);
+ int idx = lua_tointeger(L, 2);
+ int type;
+ const float * v = lastack_value(LS, R->id, &type);
+ if (v == NULL) {
+ return luaL_error(L, "Invalid ref object");
+ }
+ return index_object(L, LS, R->id, idx);
+}
+
+
+static int
+lindex(lua_State *L) {
+ int64_t id = get_id(L, 1, lua_type(L, 1));
+ int idx = luaL_checkinteger(L, 2);
+ return index_object(L, GETLS(L), id, idx);
+}
+
+
+static int
+lref_getter(lua_State *L) {
+ int type = lua_type(L, 2);
+ switch (type) {
+ case LUA_TNUMBER:
+ return ref_get_number(L);
+ case LUA_TSTRING:
+ return ref_get_key(L);
+ default:
+ return luaL_error(L, "Invalid key type %s", lua_typename(L, type));
+ }
+}
+
+static int
+id_tostring(lua_State *L, int64_t id) {
+ int type;
+ const float * v = lastack_value(GETLS(L), id, &type);
+ if (v == NULL) {
+ lua_pushstring(L, "Invalid");
+ return 1;
+ }
+ switch (type) {
+ case LINEAR_TYPE_MAT:
+ lua_pushfstring(L, "MAT (%f,%f,%f,%f : %f,%f,%f,%f : %f,%f,%f,%f : %f,%f,%f,%f)",
+ v[0],v[1],v[2],v[3],
+ v[4],v[5],v[6],v[7],
+ v[8],v[9],v[10],v[11],
+ v[12],v[13],v[14],v[15]);
+ break;
+ case LINEAR_TYPE_VEC4:
+ lua_pushfstring(L, "VEC4 (%f,%f,%f,%f)",
+ v[0], v[1], v[2], v[3]);
+ break;
+ case LINEAR_TYPE_QUAT:
+ lua_pushfstring(L, "QUAT (%f,%f,%f,%f)",
+ v[0], v[1], v[2], v[3]);
+ break;
+ default:
+ lua_pushstring(L, "Unknown");
+ break;
+ }
+ return 1;
+}
+
+static int
+lref_tostring(lua_State *L) {
+ struct refobject *R = lua_touserdata(L, 1);
+ if (R->id == 0) {
+ lua_pushstring(L, "Null");
+ return 1;
+ }
+ return id_tostring(L, R->id);
+}
+
+static int
+ltostring(lua_State *L) {
+ int64_t id = get_id(L, 1, lua_type(L, 1));
+ return id_tostring(L, id);
+}
+
+static int
+lref_gc(lua_State *L) {
+ struct refobject *R = lua_touserdata(L, 1);
+ if (R->id) {
+ lastack_unmark(GETLS(L), R->id);
+ R->id = 0;
+ }
+ return 0;
+}
+
+static int
+new_object(lua_State *L, int type, from_table_func from_table, int narray) {
+ int argn = lua_gettop(L);
+ int64_t id;
+ if (argn == narray) {
+ int i;
+ float tmp[16];
+ struct lastack *LS = GETLS(L);
+ for (i=0;i 0){
+ g_default_homogeneous_depth = lua_toboolean(L, 1) != 0;
+ return 0;
+ }
+
+ lua_pushboolean(L, g_default_homogeneous_depth ? 1 : 0);
+ return 1;
+}
+
+static int
+lpack(lua_State *L) {
+ size_t sz;
+ const char * format = luaL_checklstring(L, 1, &sz);
+ int n = lua_gettop(L);
+ int i;
+ if (n != 5 && n != 17) {
+ return luaL_error(L, "need 5 or 17 arguments , it's %d", n);
+ }
+ --n;
+ if (n != sz) {
+ return luaL_error(L, "Invalid format %s", format);
+ }
+ union {
+ float f[16];
+ uint32_t n[16];
+ } u;
+ for (i=0;iLS = lastack_new();
+ finalize(L, boxstack_gc);
+ lua_setfield(L, LUA_REGISTRYINDEX, MATH3D_STACK);
+
+ luaL_Reg l[] = {
+ { "ref", NULL },
+ { "tostring", ltostring },
+ { "matrix", lmatrix },
+ { "vector", lvector },
+ { "quaternion", lquaternion },
+ { "index", lindex },
+ { "reset", lreset },
+ { "mul", lmul },
+ { "add", ladd },
+ { "sub", lsub },
+ { "muladd", lmuladd},
+ { "srt", lsrt },
+ { "length", llength },
+ { "floor", lfloor },
+ { "ceil", lceil },
+ { "dot", ldot },
+ { "cross", lcross },
+ { "normalize", lnormalize },
+ { "transpose", ltranspose },
+ { "inverse", linverse },
+ { "lookat", llookat },
+ { "lookto", llookto },
+ { "reciprocal", lreciprocal },
+ { "todirection", ltodirection },
+ { "torotation", ltorotation },
+ { "totable", ltotable},
+ { "base_axes", lbase_axes},
+ { "transform", ltransform},
+ { "transformH", ltransform_homogeneous_point },
+ { "projmat", lprojmat },
+ { "minmax", lminmax},
+ { "lerp", llerp},
+ { "dir2radian", ldir2radian},
+ { "stacksize", lstacksize},
+ { "homogeneous_depth", lhomogeneous_depth },
+ { "pack", lpack },
+ { NULL, NULL },
+ };
+
+ luaL_newlibtable(L,l);
+ lua_pushlightuserdata(L, bs->LS);
+ luaL_setfuncs(L,l,1);
+
+ luaL_Reg ref_mt[] = {
+ { "__newindex", lref_setter },
+ { "__index", lref_getter },
+ { "__tostring", lref_tostring },
+ { "__gc", lref_gc },
+ { NULL, NULL },
+ };
+
+ lua_pushlightuserdata(L, bs->LS);
+
+ luaL_newlibtable(L,ref_mt);
+ lua_pushlightuserdata(L, bs->LS);
+ luaL_setfuncs(L,ref_mt,1);
+
+ lua_pushcclosure(L, lref, 2);
+ lua_setfield(L, -2, "ref");
+
+ return 1;
+}
+
+// util function
+
+const float *
+math3d_from_lua(lua_State *L, struct lastack *LS, int index, int type) {
+ switch(type) {
+ case LINEAR_TYPE_MAT:
+ return matrix_from_index(L, LS, index);
+ case LINEAR_TYPE_VEC4:
+ return vector_from_index(L, LS, index);
+ case LINEAR_TYPE_QUAT:
+ return quat_from_index(L, LS, index);
+ default:
+ luaL_error(L, "Invalid math3d object type %d", type);
+ }
+ return NULL;
+}
+
+const float *
+math3d_from_lua_id(lua_State *L, struct lastack *LS, int index, int *type) {
+ int64_t id = get_id(L, index, lua_type(L, index));
+ *type = LINEAR_TYPE_NONE;
+ return lastack_value(LS, id, type);
+}
diff --git a/framework/lualib-src/math3d/math3d.h b/framework/lualib-src/math3d/math3d.h
new file mode 100755
index 0000000..0ce4ede
--- /dev/null
+++ b/framework/lualib-src/math3d/math3d.h
@@ -0,0 +1,24 @@
+#ifndef math3d_lua_binding_h
+#define math3d_lua_binding_h
+
+#include "linalg.h"
+#include
+
+struct boxstack {
+ struct lastack *LS;
+};
+
+struct refobject {
+ int64_t id;
+};
+
+#define MATH3D_STACK "_MATHSTACK"
+
+int math3d_homogeneous_depth();
+
+// binding functions
+
+const float * math3d_from_lua(lua_State *L, struct lastack *LS, int index, int type);
+const float * math3d_from_lua_id(lua_State *L, struct lastack *LS, int index, int *type);
+
+#endif
diff --git a/framework/lualib-src/math3d/math3dfunc.h b/framework/lualib-src/math3d/math3dfunc.h
new file mode 100755
index 0000000..218f580
--- /dev/null
+++ b/framework/lualib-src/math3d/math3dfunc.h
@@ -0,0 +1,45 @@
+#ifndef math3d_func_h
+#define math3d_func_h
+
+#include "linalg.h"
+
+#define LINEAR_TYPE_NUM LINEAR_TYPE_COUNT
+
+// math functions
+
+void math3d_make_srt(struct lastack *LS, const float *s, const float *r, const float *t);
+void math3d_make_quat_from_euler(struct lastack *LS, float x, float y, float z);
+void math3d_make_quat_from_axis(struct lastack *LS, const float *axis, float radian);
+int math3d_mul_object(struct lastack *LS, const float *lval, const float *rval, int ltype, int rtype, float tmp[16]);
+void math3d_add_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]);
+void math3d_sub_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]);
+void math3d_decompose_matrix(struct lastack *LS, const float *mat);
+void math3d_decompose_rot(const float mat[16], float quat[4]);
+int math3d_decompose_scale(const float mat[16], float scale[4]);
+void math3d_quat_to_matrix(struct lastack *LS, const float quat[4]);
+void math3d_matrix_to_quat(struct lastack *LS, const float mat[16]);
+float math3d_length(const float *v3);
+void math3d_floor(struct lastack *LS, const float v[4]);
+void math3d_ceil(struct lastack *LS, const float v[4]);
+float math3d_dot(const float v1[4], const float v2[4]);
+void math3d_cross(struct lastack *LS, const float v1[4], const float v2[4]);
+void math3d_mulH(struct lastack *LS, const float mat[16], const float vec[4]);
+void math3d_normalize_vector(struct lastack *LS, const float v[4]);
+void math3d_normalize_quat(struct lastack *LS, const float v[4]);
+void math3d_inverse_matrix(struct lastack *LS, const float mat[16]);
+void math3d_inverse_quat(struct lastack *LS, const float quat[4]);
+void math3d_transpose_matrix(struct lastack *LS, const float mat[16]);
+void math3d_lookat_matrix(struct lastack *LS, int direction, const float eye[3], const float at[3], const float *up);
+void math3d_reciprocal(struct lastack *LS, const float v[4]);
+void math3d_quat_to_viewdir(struct lastack *LS, const float q[4]);
+void math3d_rotmat_to_viewdir(struct lastack *LS, const float m[16]);
+void math3d_viewdir_to_quat(struct lastack *LS, const float v[3]);
+void math3d_frustumLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth);
+void math3d_orthoLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth);
+void math3d_base_axes(struct lastack *LS, const float forward[4]);
+void math3d_quat_transform(struct lastack *LS, const float quat[4], const float v[4]);
+void math3d_rotmat_transform(struct lastack *LS, const float mat[16], const float v[4]);
+void math3d_minmax(struct lastack *LS, const float mat[16], const float v[4], float minv[4], float maxv[4]);
+void math3d_lerp(struct lastack *LS, const float v0[4], const float v1[4], float ratio, float r[4]);
+void math3d_dir2radian(struct lastack *LS, const float v[4], float radians[2]);
+#endif
diff --git a/framework/lualib-src/math3d/mathadapter.c b/framework/lualib-src/math3d/mathadapter.c
new file mode 100755
index 0000000..149f3df
--- /dev/null
+++ b/framework/lualib-src/math3d/mathadapter.c
@@ -0,0 +1,538 @@
+#define LUA_LIB
+
+#include
+#include
+#include
+#include "math3d.h"
+#include "linalg.h"
+
+typedef enum {
+ SET_Mat = 0x01,
+ SET_Vec = 0x02,
+ SET_Array = 0x10,
+ SET_Unknown,
+}StackElemType;
+
+static inline void *
+get_pointer(lua_State *L, struct lastack *LS, int index, int type) {
+ return (void *)math3d_from_lua(L, LS, index, type);
+}
+
+static void *
+getopt_pointer(lua_State *L, struct lastack *LS, int index, int type) {
+ if (lua_isnoneornil(L, index)) {
+ return NULL;
+ } else {
+ return get_pointer(L, LS, index, type);
+ }
+}
+
+static void *
+get_pointer_variant(lua_State *L, struct lastack *LS, int index, int elemtype) {
+ if (elemtype & SET_Mat) {
+ return get_pointer(L, LS, index, LINEAR_TYPE_MAT);
+ } else {
+ return get_pointer(L, LS, index, LINEAR_TYPE_VEC4);
+ }
+}
+
+// upvalue1 mathstack
+// upvalue2 cfunction
+// upvalue3 from
+static int
+lmatrix_adapter_1(lua_State *L) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ int from = lua_tointeger(L, lua_upvalueindex(3));
+ void * v = get_pointer(L, LS, from, LINEAR_TYPE_MAT);
+ lua_settop(L, from-1);
+ lua_pushlightuserdata(L, v);
+ return f(L);
+}
+
+static int
+lmatrix_adapter_2(lua_State *L) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ int from = lua_tointeger(L, lua_upvalueindex(3));
+ void * v1 = getopt_pointer(L, LS, from, LINEAR_TYPE_MAT);
+ void * v2 = getopt_pointer(L, LS, from+1, LINEAR_TYPE_MAT);
+ lua_settop(L, from-1);
+ if (v1) {
+ lua_pushlightuserdata(L, v1);
+ } else {
+ lua_pushnil(L);
+ }
+ if (v2) {
+ lua_pushlightuserdata(L, v2);
+ } else {
+ lua_pushnil(L);
+ }
+ return f(L);
+}
+
+static int
+lmatrix_adapter_var(lua_State *L) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ int from = lua_tointeger(L, lua_upvalueindex(3));
+ int i;
+ int top = lua_gettop(L);
+ for (i=from;i<=top;i++) {
+ void * v = getopt_pointer(L, LS, i, LINEAR_TYPE_MAT);
+ if (v) {
+ lua_pushlightuserdata(L, v);
+ lua_replace(L, i);
+ }
+ }
+ return f(L);
+}
+
+// upvalue1 : userdata mathstack
+// cfunction original function
+// integer from
+// integer n
+static int
+lbind_matrix(lua_State *L) {
+ if (!lua_iscfunction(L, 1))
+ return luaL_error(L, "need a c function");
+ if (lua_getupvalue(L, 1, 1) != NULL)
+ luaL_error(L, "Only support light cfunction");
+ int from = luaL_checkinteger(L, 2);
+ int n = luaL_optinteger(L, 3, 0);
+ lua_CFunction f;
+ switch (n) {
+ case 0:
+ f = lmatrix_adapter_var;
+ break;
+ case 1:
+ f = lmatrix_adapter_1;
+ break;
+ case 2:
+ f = lmatrix_adapter_2;
+ break;
+ default:
+ return luaL_error(L, "Only support 1,2,0(vararg) now");
+ }
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_pushinteger(L, from);
+ lua_pushcclosure(L, f, 4);
+ return 1;
+}
+
+static int
+lvector(lua_State *L) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ const int from = lua_tointeger(L, lua_upvalueindex(3));
+
+ const int top = lua_gettop(L);
+
+ int ii;
+
+ for (ii = from; ii <= top; ++ii) {
+ if (!lua_isnil(L, ii)) {
+ void* p = get_pointer(L, LS, ii, LINEAR_TYPE_VEC4);
+ lua_pushlightuserdata(L, p);
+ lua_replace(L, ii);
+ }
+ }
+
+ return f(L);
+}
+
+static int
+lbind_vector(lua_State *L) {
+ if (!lua_iscfunction(L, 1))
+ return luaL_error(L, "need a c function");
+ if (lua_getupvalue(L, 1, 1) != NULL)
+ luaL_error(L, "Only support light cfunction");
+
+ luaL_checkinteger(L, 2);
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1); // cfunction
+ lua_pushvalue(L, 2); // from
+ lua_pushcclosure(L, lvector, 3);
+ return 1;
+}
+
+static uint8_t
+check_elem_type(lua_State *L, struct lastack *LS, int index) {
+ if (lua_type(L, index) == LUA_TTABLE) {
+ const int fieldtype = lua_getfield(L, index, "n");
+ lua_pop(L, 1);
+
+ if (fieldtype != LUA_TNIL){
+ const int elemtype = lua_geti(L, index, 1);
+ if (elemtype != LUA_TTABLE) {
+ int type;
+ math3d_from_lua_id(L, LS, -1, &type);
+ lua_pop(L, 1);
+ return SET_Array | (type == LINEAR_TYPE_MAT ? SET_Mat : SET_Vec);
+ }
+
+ lua_pop(L, 1);
+ return SET_Array | (lua_rawlen(L, index) >= 12 ? SET_Mat : SET_Vec);
+ }
+ return lua_rawlen(L, index) >= 12 ? SET_Mat : SET_Vec;
+ }
+
+ int type;
+ math3d_from_lua_id(L, LS, index, &type);
+ return type == LINEAR_TYPE_MAT ? SET_Mat : SET_Vec;
+}
+
+static void
+unpack_table_on_stack(lua_State *L, struct lastack *LS, int from, int top, int elemtype) {
+ int stackidx;
+ for (stackidx = from; stackidx <= top; ++stackidx) {
+ if (lua_getfield(L, stackidx, "n") != LUA_TNIL) {
+ const int num = (int)lua_tointeger(L, -1);
+ lua_pop(L, 1); // pop 'n'
+
+ const int tablenum = (int)lua_rawlen(L, stackidx);
+ if (num != tablenum) {
+ luaL_error(L, "'n' field: %d not equal to table count: %d", num, tablenum);
+ }
+
+ int tblidx;
+ for (tblidx = 0; tblidx < num; ++tblidx) {
+ lua_geti(L, stackidx, tblidx + 1);
+ void * v = get_pointer_variant(L, LS, -1, elemtype);
+ if (v) {
+ lua_pop(L, 1); // pop lua_geti value
+ lua_pushlightuserdata(L, v);
+ } else {
+ luaL_checktype(L, -1, LUA_TTABLE);
+ }
+
+ // v == NULL will not pop, make it in the stack
+ }
+ }
+ }
+
+ int ii;
+ for (ii = 0; ii <= top - from; ++ii) {
+ lua_remove(L, from);
+ }
+}
+
+static void
+convert_stack_value(lua_State *L, struct lastack *LS, int from, int top, int elemtype) {
+ int i;
+ for (i = from; i <= top; i++) {
+ void * v = get_pointer_variant(L, LS, i, elemtype);
+ if (v) {
+ lua_pushlightuserdata(L, v);
+ lua_replace(L, i);
+ }
+ }
+}
+
+// upvalue1 mathstack
+// upvalue2 matrix cfunction
+// upvalue3 vector cfunction
+// upvalue4 integer from
+static int
+lvariant(lua_State *L) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ const int from = lua_tointeger(L, lua_upvalueindex(4));
+ const int top = lua_gettop(L);
+ const uint8_t elemtype = check_elem_type(L, LS, from);
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex((elemtype & SET_Mat) ? 2 : 3));
+ if (elemtype & SET_Array) {
+ unpack_table_on_stack(L, LS, from, top, elemtype);
+ } else {
+ convert_stack_value(L, LS, from, top, elemtype);
+ }
+ return f(L);
+}
+
+// upvalue1 : userdata mathstack
+// cfunction original function for matrix
+// cfunction original function for vector
+// integer from
+static int
+lbind_variant(lua_State *L) {
+ if (!lua_iscfunction(L, 1))
+ return luaL_error(L, "need a c function");
+ if (lua_getupvalue(L, 1, 1) != NULL)
+ luaL_error(L, "Only support light cfunction");
+ if (!lua_iscfunction(L, 2))
+ return luaL_error(L, "need a c function");
+ if (lua_getupvalue(L, 2, 1) != NULL)
+ luaL_error(L, "Only support light cfunction");
+ luaL_checkinteger(L, 3);
+
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, 3);
+
+ lua_pushcclosure(L, lvariant, 4);
+ return 1;
+}
+
+static int
+lformat(lua_State *L, const char *format) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ int from = lua_tointeger(L, lua_upvalueindex(4));
+ int i;
+ int top = lua_gettop(L);
+ void *v = NULL;
+ for (i=0;format[i];i++) {
+ int index = from + i;
+ if (index > top)
+ luaL_error(L, "Invalid format string %s", format);
+ switch(format[i]) {
+ case 'm':
+ v = get_pointer(L, LS, index, LINEAR_TYPE_MAT);
+ break;
+ case 'v':
+ v = get_pointer(L, LS, index, LINEAR_TYPE_VEC4);
+ break;
+ case 'q':
+ v = get_pointer(L, LS, index, LINEAR_TYPE_QUAT);
+ break;
+ default:
+ luaL_error(L, "Invalid format string %s", format);
+ break;
+ }
+ lua_pushlightuserdata(L, v);
+ lua_replace(L, index);
+ }
+ return f(L);
+}
+
+static int
+lformat_function(lua_State *L) {
+ lua_CFunction getformat = lua_tocfunction(L, lua_upvalueindex(3));
+ if (getformat(L) != 1 || lua_type(L, -1) != LUA_TLIGHTUSERDATA)
+ luaL_error(L, "Invalid format C function");
+ const char *format = (const char *)lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return lformat(L, format);
+}
+
+static int
+lformat_string(lua_State *L) {
+ const char *format = lua_tostring(L, lua_upvalueindex(3));
+ return lformat(L, format);
+}
+
+// upvalue1: userdata mathstack
+// cfunction original function
+// cfunction function return (void *)format
+// integer from
+static int
+lbind_format(lua_State *L) {
+ if (!lua_iscfunction(L, 1))
+ return luaL_error(L, "need a c function");
+ if (lua_getupvalue(L, 1, 1) != NULL)
+ luaL_error(L, "Only support light cfunction");
+ int string_version = 0;
+ if (lua_isstring(L, 2)) {
+ string_version = 1;
+ } else if (!lua_iscfunction(L, 2)) {
+ return luaL_error(L, "need a c format function or string");
+ }
+ if (lua_getupvalue(L, 2, 1) != NULL)
+ luaL_error(L, "Only support light cfunction");
+ luaL_checkinteger(L, 3);
+
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, 3);
+
+ if (string_version) {
+ lua_pushcclosure(L, lformat_string, 4);
+ } else {
+ lua_pushcclosure(L, lformat_function, 4);
+ }
+ return 1;
+}
+
+struct stack_buf {
+ float mat[16];
+ struct stack_buf *prev;
+};
+
+static int
+get_n(lua_State *L, int n, struct stack_buf *prev) {
+ if (n == 0) {
+ struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ size_t sz = 0;
+ const char *format = lua_tolstring(L, lua_upvalueindex(3), &sz);
+ int ret = f(L);
+ if (ret == 0) {
+ lua_settop(L, 0);
+ } else {
+ int top = lua_gettop(L);
+ if (ret != top) {
+ if (ret < top && ret != 0) {
+ int remove = top-ret;
+ lua_rotate(L, 1, -remove);
+ }
+ lua_settop(L, ret);
+ }
+ }
+ luaL_checkstack(L, (int)sz, NULL);
+ int i = (int)sz - 1;
+ while (prev) {
+ switch(format[i]) {
+ case 'm':
+ lastack_pushmatrix(LS, prev->mat);
+ break;
+ case 'v':
+ lastack_pushvec4(LS, prev->mat);
+ break;
+ case 'q':
+ lastack_pushquat(LS, prev->mat);
+ break;
+ default:
+ luaL_error(L,"Invalid getter format %s", format);
+ break;
+ }
+ int64_t id = lastack_pop(LS);
+ lua_pushlightuserdata(L, (void *)id);
+ lua_insert(L, ret+1);
+
+ prev = prev->prev;
+ --i;
+ }
+ return ret + (int)sz;
+ }
+ struct stack_buf buf;
+ buf.prev = prev;
+ lua_pushlightuserdata(L, (void *)buf.mat);
+ return get_n(L, n-1, &buf);
+}
+
+static int
+lgetter(lua_State *L) {
+ size_t n = 0;
+ lua_tolstring(L, lua_upvalueindex(3), &n);
+ luaL_checkstack(L, (int)(n + LUA_MINSTACK), NULL);
+ return get_n(L, (int)n, NULL);
+}
+
+// upvalue1 : userdata mathstack
+// cfunction original getter
+// string format "mvq" , m for matrix, v for vector4, q for quat
+static int
+lbind_getter(lua_State *L) {
+ if (!lua_iscfunction(L, 1))
+ return luaL_error(L, "need a c function");
+ luaL_checkstring(L, 2);
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_pushcclosure(L, lgetter, 3);
+ return 1;
+}
+
+static int
+loutput_object(lua_State *L, int ltype) {
+ lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
+ int retn = f(L);
+ int from = lua_tointeger(L, lua_upvalueindex(3));
+ int top = lua_gettop(L);
+ if (retn > from) {
+ lua_settop(L, retn);
+ top = retn;
+ }
+ from = top - retn + from;
+ int i;
+ struct lastack *LS = (struct lastack *)lua_touserdata(L, lua_upvalueindex(1));
+
+ for (i=from;i<=top;i++) {
+ if (lua_type(L, i) != LUA_TLIGHTUSERDATA) {
+ return luaL_error(L, "ret %d should be a lightuserdata", i);
+ }
+ const float *v = (const float *)lua_touserdata(L, i);
+ lastack_pushobject(LS, v, ltype);
+ lua_pushlightuserdata(L, (void *)(lastack_pop(LS)));
+ lua_replace(L, i);
+ }
+ return retn;
+}
+
+static int
+loutput_matrix(lua_State *L) {
+ return loutput_object(L, LINEAR_TYPE_MAT);
+}
+
+static int
+loutput_vector(lua_State *L) {
+ return loutput_object(L, LINEAR_TYPE_VEC4);
+}
+
+static int
+loutput_quat(lua_State *L) {
+ return loutput_object(L, LINEAR_TYPE_QUAT);
+}
+
+// upvalue1 : userdata mathstack
+// cfunction original output
+// integer from
+static int
+lbind_output(lua_State *L, lua_CFunction output_func) {
+ if (!lua_iscfunction(L, 1))
+ return luaL_error(L, "need a c function");
+ luaL_checkinteger(L, 2);
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_pushcclosure(L, output_func, 3);
+ return 1;
+}
+
+static int
+lbind_output_matrix(lua_State *L) {
+ return lbind_output(L, loutput_matrix);
+}
+
+static int
+lbind_output_vector(lua_State *L) {
+ return lbind_output(L, loutput_vector);
+}
+
+static int
+lbind_output_quat(lua_State *L) {
+ return lbind_output(L, loutput_quat);
+}
+
+LUAMOD_API int
+luaopen_math3d_adapter(lua_State *L) {
+ luaL_checkversion(L);
+
+ luaL_Reg l[] = {
+ { "matrix", lbind_matrix },
+ { "vector", lbind_vector},
+ { "variant", lbind_variant },
+ { "format", lbind_format },
+ { "getter", lbind_getter },
+ { "output_matrix", lbind_output_matrix },
+ { "output_vector", lbind_output_vector },
+ { "output_quat", lbind_output_quat },
+ { NULL, NULL },
+ };
+
+ luaL_newlibtable(L, l);
+
+ if (lua_getfield(L, LUA_REGISTRYINDEX, MATH3D_STACK) != LUA_TUSERDATA) {
+ return luaL_error(L, "request 'math3d' first");
+ }
+ struct boxstack * bs = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ lua_pushlightuserdata(L, bs->LS);
+
+ luaL_setfuncs(L,l,1);
+
+ return 1;
+}
diff --git a/framework/lualib-src/math3d/mathfunc.cpp b/framework/lualib-src/math3d/mathfunc.cpp
new file mode 100755
index 0000000..afe5e73
--- /dev/null
+++ b/framework/lualib-src/math3d/mathfunc.cpp
@@ -0,0 +1,412 @@
+#define LUA_LIB
+#define GLM_ENABLE_EXPERIMENTAL
+
+#include
+
+extern "C" {
+ #include "linalg.h"
+ #include "math3dfunc.h"
+}
+
+#include "util.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static const glm::vec4 XAXIS(1, 0, 0, 0);
+static const glm::vec4 YAXIS(0, 1, 0, 0);
+static const glm::vec4 ZAXIS(0, 0, 1, 0);
+static const glm::vec4 WAXIS(0, 0, 0, 1);
+
+static const glm::vec4 NXAXIS = -XAXIS;
+static const glm::vec4 NYAXIS = -YAXIS;
+static const glm::vec4 NZAXIS = -ZAXIS;
+
+void
+math3d_make_srt(struct lastack *LS, const float *scale, const float *rot, const float *translate) {
+ glm::mat4x4 srt;
+ if (scale) {
+ srt = glm::mat4x4(1);
+ srt[0][0] = scale[0];
+ srt[1][1] = scale[1];
+ srt[2][2] = scale[2];
+ }
+ if (rot) {
+ const glm::quat * q = (const glm::quat *)rot;
+ if (scale) {
+ srt = glm::mat4x4(*q) * srt;
+ } else {
+ srt = glm::mat4x4(*q);
+ }
+ } else if (scale == NULL) {
+ srt = glm::mat4x4(1);
+ }
+ if (translate) {
+ srt[3][0] = translate[0];
+ srt[3][1] = translate[1];
+ srt[3][2] = translate[2];
+ srt[3][3] = 1;
+ }
+ lastack_pushmatrix(LS, &srt[0][0]);
+}
+
+void
+math3d_make_quat_from_euler(struct lastack *LS, float x, float y, float z) {
+ glm::vec3 r(x,y,z);
+ glm::quat q(r);
+ lastack_pushquat(LS, &q[0]);
+}
+
+void
+math3d_make_quat_from_axis(struct lastack *LS, const float *axis, float radian) {
+ glm::vec3 a(axis[0],axis[1],axis[2]);
+ glm::quat q = glm::angleAxis(radian, a);
+
+ lastack_pushquat(LS, &q[0]);
+}
+
+#define BINTYPE(v1, v2) (((v1) << LINEAR_TYPE_BITS_NUM) + (v2))
+#define MAT(v) (*(const glm::mat4x4 *)(v))
+#define VEC(v) (*(const glm::vec4 *)(v))
+#define VEC3(v) (*(const glm::vec3 *)(v))
+#define QUAT(v) (*(const glm::quat *)(v))
+
+int
+math3d_mul_object(struct lastack *LS, const float *val0, const float *val1, int ltype, int rtype, float tmp[16]) {
+ int type = BINTYPE(ltype, rtype);
+
+ glm::mat4x4 &mat = *(glm::mat4x4 *)tmp;
+ glm::vec4 &vec = *(glm::vec4 *)tmp;
+
+ switch (type) {
+ case BINTYPE(LINEAR_TYPE_MAT,LINEAR_TYPE_MAT):
+ mat = MAT(val0) * MAT(val1);
+ return LINEAR_TYPE_MAT;
+ case BINTYPE(LINEAR_TYPE_VEC4, LINEAR_TYPE_NUM):
+ vec = VEC(val0) * val1[0];
+ return LINEAR_TYPE_VEC4;
+ case BINTYPE(LINEAR_TYPE_NUM, LINEAR_TYPE_VEC4):
+ vec = val0[0] * VEC(val1);
+ return LINEAR_TYPE_VEC4;
+ case BINTYPE(LINEAR_TYPE_QUAT, LINEAR_TYPE_QUAT): {
+ glm::quat &quat = *(glm::quat *)tmp;
+ quat = QUAT(val0) * QUAT(val1);
+ return LINEAR_TYPE_QUAT;
+ }
+ case BINTYPE(LINEAR_TYPE_VEC4, LINEAR_TYPE_VEC4):
+ vec = VEC(val0) * VEC(val1);
+ return LINEAR_TYPE_VEC4;
+ }
+
+ return LINEAR_TYPE_NONE;
+}
+
+void
+math3d_add_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]){
+ *(glm::vec4*)r = VEC(lhs) + VEC(rhs);
+}
+
+void
+math3d_sub_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]){
+ *(glm::vec4*)r = VEC(lhs) - VEC(rhs);
+}
+
+// epsilon for pow2
+//#define EPSILON 0.00001f
+// glm::equal(dot , 1.0f, EPSILON)
+
+static inline int
+equal_one(float f) {
+ union {
+ float f;
+ uint32_t n;
+ } u;
+ u.f = f;
+ return ((u.n + 0x1f) & ~0x3f) == 0x3f800000; // float 1
+}
+
+int
+math3d_decompose_scale(const float mat[16], float scale[4]) {
+ int ii;
+ scale[3] = 0;
+ for (ii = 0; ii < 3; ++ii) {
+ const float * v = (const float *)&MAT(mat)[ii];
+ float dot = glm::dot(VEC3(v),VEC3(v));
+ if (equal_one(dot)) {
+ scale[ii] = 1.0f;
+ } else {
+ scale[ii] = sqrtf(dot);
+ if (scale[ii] == 0) {
+ // invalid scale, use 1 instead
+ scale[0] = scale[1] = scale[2] = 1.0f;
+ return 1;
+ }
+ }
+ }
+ if (scale[0] == 1.0f && scale[1] == 1.0f && scale[2] == 1.0f) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+math3d_decompose_rot(const float mat[16], float quat[4]) {
+ glm::quat &q = *(glm::quat *)quat;
+ glm::mat3x3 rotMat(MAT(mat));
+ float scale[4];
+ if (math3d_decompose_scale(mat, scale) == 0) {
+ int ii;
+ for (ii = 0; ii < 3; ++ii) {
+ rotMat[ii] /= scale[ii];
+ }
+ }
+ q = glm::quat_cast(rotMat);
+}
+
+void
+math3d_decompose_matrix(struct lastack *LS, const float *mat) {
+ const glm::mat4x4 &m = *(const glm::mat4x4 *)mat;
+ float trans[4] = { m[3][0] , m[3][1], m[3][2], 1 };
+ float scale[4];
+ glm::mat3x3 rotMat(m);
+ if (!math3d_decompose_scale(mat, scale)) {
+ int ii;
+ for (ii = 0; ii < 3; ++ii) {
+ rotMat[ii] /= scale[ii];
+ }
+ }
+ glm::quat q = glm::quat_cast(rotMat);
+ lastack_pushvec4(LS, trans);
+ lastack_pushquat(LS, &q.x);
+ lastack_pushvec4(LS, scale);
+}
+
+float
+math3d_length(const float *v) {
+ return glm::length(VEC3(v));
+}
+
+void
+math3d_floor(struct lastack *LS, const float v[4]) {
+ glm::vec4 vv(glm::floor(VEC3(v)), 0.f);
+ lastack_pushvec4(LS, &vv.x);
+}
+
+void
+math3d_ceil(struct lastack *LS, const float v[4]) {
+ glm::vec4 vv(glm::ceil(VEC3(v)), 0.f);
+ lastack_pushvec4(LS, &vv.x);
+}
+
+float
+math3d_dot(const float v1[4], const float v2[4]) {
+ return glm::dot(VEC3(v1), VEC3(v2));
+}
+
+void
+math3d_cross(struct lastack *LS, const float v1[4], const float v2[4]) {
+ glm::vec4 r(glm::cross(VEC3(v1), VEC3(v2)), 0);
+ lastack_pushvec4(LS, &r.x);
+}
+
+void
+math3d_mulH(struct lastack *LS, const float mat[16], const float vec[4]) {
+ glm::vec4 r;
+
+ if (vec[3] != 1.f){
+ float tmp[4] = { vec[0], vec[1], vec[2], 1 };
+ r = MAT(mat) * VEC(tmp);
+ } else {
+ r = MAT(mat) * VEC(vec);
+ }
+
+ if (r.w != 0) {
+ r /= fabs(r.w);
+ r.w = 1.f;
+ }
+
+ lastack_pushvec4(LS, &r.x);
+}
+
+void
+math3d_normalize_vector(struct lastack *LS, const float v[4]) {
+ glm::vec4 r(glm::normalize(VEC3(v)), v[3]);
+ lastack_pushvec4(LS, &r.x);
+}
+
+void
+math3d_normalize_quat(struct lastack *LS, const float v[4]) {
+ glm::quat q = glm::normalize(QUAT(v));
+ lastack_pushquat(LS, &q.x);
+}
+
+void
+math3d_transpose_matrix(struct lastack *LS, const float mat[16]) {
+ glm::mat4x4 r = glm::transpose(MAT(mat));
+ lastack_pushmatrix(LS, &r[0][0]);
+}
+
+void
+math3d_inverse_matrix(struct lastack *LS, const float mat[16]) {
+ glm::mat4x4 r = glm::inverse(MAT(mat));
+ lastack_pushmatrix(LS, &r[0][0]);
+}
+
+void
+math3d_inverse_quat(struct lastack *LS, const float quat[4]) {
+ glm::quat q = glm::inverse(QUAT(quat));
+ lastack_pushquat(LS, &q.x);
+}
+
+void
+math3d_lookat_matrix(struct lastack *LS, int direction, const float eye[3], const float at[3], const float *up) {
+ glm::mat4x4 m;
+ if (up == NULL) {
+ static const float default_up[3] = {0,1,0};
+ up = default_up;
+ }
+ if (direction) {
+ const glm::vec3 vat = VEC3(eye) + VEC3(at);
+ m = glm::lookAtLH(VEC3(eye), vat, VEC3(up));
+ } else {
+ m = glm::lookAtLH(VEC3(eye), VEC3(at), VEC3(up));
+ }
+ lastack_pushmatrix(LS, &m[0][0]);
+}
+
+void
+math3d_quat_to_matrix(struct lastack *LS, const float quat[4]) {
+ glm::mat4x4 m = glm::mat4x4(QUAT(quat));
+ lastack_pushmatrix(LS, &m[0][0]);
+}
+
+void
+math3d_matrix_to_quat(struct lastack *LS, const float mat[16]) {
+ glm::quat q = glm::quat_cast(MAT(mat));
+ lastack_pushquat(LS, &q.x);
+}
+
+void
+math3d_reciprocal(struct lastack *LS, const float v[4]) {
+ glm::vec4 vv = VEC(v);
+ vv = 1.f / vv;
+ vv[3] = v[3];
+ lastack_pushvec4(LS, &vv.x);
+}
+
+void
+math3d_quat_to_viewdir(struct lastack *LS, const float q[4]) {
+ glm::vec4 d = glm::rotate(QUAT(q), glm::vec4(0, 0, 1, 0));
+ lastack_pushvec4(LS, &d.x);
+}
+
+void
+math3d_rotmat_to_viewdir(struct lastack *LS, const float m[16]) {
+ glm::vec4 d = MAT(m) * glm::vec4(0, 0, 1, 0);
+ lastack_pushvec4(LS, &d.x);
+}
+
+void
+math3d_viewdir_to_quat(struct lastack *LS, const float v[3]) {
+ glm::quat q(glm::vec3(0, 0, 1), VEC3(v));
+ lastack_pushquat(LS, &q.x);
+}
+
+void
+math3d_frustumLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth) {
+ glm::mat4x4 mat = homogeneous_depth ?
+ glm::frustumLH_NO(left, right, bottom, top, near, far) :
+ glm::frustumLH_ZO(left, right, bottom, top, near, far);
+ lastack_pushmatrix(LS, &mat[0][0]);
+}
+
+void
+math3d_orthoLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth) {
+ glm::mat4x4 mat = homogeneous_depth ?
+ glm::orthoLH_NO(left, right, bottom, top, near, far) :
+ glm::orthoLH_ZO(left, right, bottom, top, near, far);
+ lastack_pushmatrix(LS, &mat[0][0]);
+}
+
+void
+math3d_base_axes(struct lastack *LS, const float forward[4]) {
+ glm::vec4 right, up;
+
+ if (is_equal(VEC(forward), ZAXIS)) {
+ up = YAXIS;
+ right = XAXIS;
+ } else {
+ if (is_equal(VEC(forward), YAXIS)) {
+ up = NZAXIS;
+ right = XAXIS;
+ } else if (is_equal(VEC(forward), NYAXIS)) {
+ up = ZAXIS;
+ right = XAXIS;
+ } else {
+ right = glm::vec4(glm::normalize(glm::cross(VEC3(&YAXIS.x), VEC3(forward))), 0);
+ up = glm::vec4(glm::normalize(glm::cross(VEC3(forward), VEC3(&right.x))), 0);
+ }
+ }
+
+ lastack_pushvec4(LS, &up.x);
+ lastack_pushvec4(LS, &right.x);
+}
+
+void
+math3d_quat_transform(struct lastack *LS, const float quat[4], const float v[4]){
+ const glm::vec4 vv = glm::rotate(QUAT(quat), VEC(v));
+ lastack_pushvec4(LS, &vv.x);
+}
+
+void
+math3d_rotmat_transform(struct lastack *LS, const float mat[16], const float v[4]){
+ const glm::vec4 vv = MAT(mat) * VEC(v);
+ lastack_pushvec4(LS, &vv.x);
+}
+
+void
+math3d_minmax(struct lastack *LS, const float mat[16], const float v[4], float minv[4], float maxv[4]){
+ const glm::vec4 vv = mat ? MAT(mat) * VEC(v) : VEC(v);
+ *(glm::vec4*)maxv = glm::max(vv, VEC(maxv));
+ *(glm::vec4*)minv = glm::min(vv, VEC(minv));
+}
+
+void
+math3d_lerp(struct lastack *LS, const float v0[4], const float v1[4], float ratio, float r[4]){
+ *(glm::vec4*)r = glm::lerp(VEC(v0), VEC(v1), ratio);
+}
+
+void
+math3d_dir2radian(struct lastack *LS, const float v[4], float radians[2]){
+ const float PI = float(M_PI);
+ const float HALF_PI = 0.5f * PI;
+
+ if (is_equal(v[1], 1.f)){
+ radians[0] = -HALF_PI;
+ radians[1] = 0.f;
+ } else if (is_equal(v[1], -1.f)){
+ radians[0] = HALF_PI;
+ radians[1] = 0.f;
+ } else if (is_equal(v[0], 1.f)){
+ radians[0] = 0.f;
+ radians[1] = HALF_PI;
+ } else if (is_equal(v[0], -1.f)){
+ radians[0] = 0.f;
+ radians[1] = -HALF_PI;
+ } else if (is_equal(v[2], 1.f)){
+ radians[0] = 0.f;
+ radians[1] = 0.f;
+ } else if (is_equal(v[2], -1.f)){
+ radians[0] = 0.f;
+ radians[1] = PI;
+ } else {
+ radians[0] = is_zero(v[1]) ? 0.f : std::asin(-v[1]);
+ radians[1] = is_zero(v[0]) ? 0.f : std::atan2(v[0], v[2]);
+ }
+}
diff --git a/framework/lualib-src/math3d/refstack.h b/framework/lualib-src/math3d/refstack.h
new file mode 100755
index 0000000..fcec65b
--- /dev/null
+++ b/framework/lualib-src/math3d/refstack.h
@@ -0,0 +1,107 @@
+#ifndef linear_algebra_refstack_h
+#define linear_algebra_refstack_h
+
+#include
+#include
+
+#define MAX_REF_STACK 128
+
+struct ref_slot {
+ int stack_id;
+ int lua_id;
+};
+
+struct ref_stack {
+ int top;
+ int reftop;
+ lua_State *L;
+ struct ref_slot s[MAX_REF_STACK];
+};
+
+static inline void
+refstack_init(struct ref_stack *RS, lua_State *L) {
+ RS->top = 0;
+ RS->reftop = 0;
+ RS->L = L;
+}
+
+static inline void
+refstack_push(struct ref_stack *RS) {
+ ++RS->top;
+}
+
+static inline void
+refstack_pop(struct ref_stack *RS) {
+ --RS->top;
+ if (RS->reftop > 0) {
+ if (RS->s[RS->reftop-1].stack_id == RS->top) {
+ --RS->reftop;
+ }
+ }
+}
+
+static inline void
+refstack_2_1(struct ref_stack *RS) {
+ refstack_pop(RS);
+ refstack_pop(RS);
+ refstack_push(RS);
+}
+
+static inline void
+refstack_1_1(struct ref_stack *RS) {
+ refstack_pop(RS);
+ refstack_push(RS);
+}
+
+static inline void
+refstack_pushref(struct ref_stack *RS, int lua_id) {
+ if (lua_id < 0) {
+ refstack_push(RS);
+ return;
+ }
+ if (RS->reftop >= MAX_REF_STACK)
+ luaL_error(RS->L, "ref stack overflow");
+ struct ref_slot *s = &RS->s[RS->reftop++];
+ s->stack_id = RS->top++;
+ s->lua_id = lua_id;
+}
+
+static inline int
+refstack_topid(struct ref_stack *RS) {
+ if (RS->reftop > 0) {
+ struct ref_slot *s = &RS->s[RS->reftop-1];
+ if (s->stack_id == RS->top-1) {
+ return s->lua_id;
+ }
+ }
+ return -1;
+}
+
+static inline void
+refstack_swap(struct ref_stack *RS) {
+ int top = refstack_topid(RS);
+ refstack_pop(RS);
+ int newtop = refstack_topid(RS);
+ refstack_pop(RS);
+ refstack_pushref(RS, top);
+ refstack_pushref(RS, newtop);
+}
+
+static inline void
+refstack_dup(struct ref_stack *RS, int index) {
+ int i;
+ int lua_id = -1;
+ int stack_id = RS->top - index;
+ for (i=RS->reftop-1;i>=0;i--) {
+ struct ref_slot *s = &RS->s[i];
+ if (s->stack_id == stack_id) {
+ lua_id = s->lua_id;
+ break;
+ }
+ if (s->stack_id < stack_id)
+ break;
+ }
+ refstack_pushref(RS, lua_id);
+}
+
+#endif
diff --git a/framework/lualib-src/math3d/test.lua b/framework/lualib-src/math3d/test.lua
new file mode 100755
index 0000000..5a8d212
--- /dev/null
+++ b/framework/lualib-src/math3d/test.lua
@@ -0,0 +1,207 @@
+local math3d = require "math3d"
+
+local ref1 = math3d.ref()
+
+ref1.m = {
+ s = 10,
+ r = {
+ axis = {1, 0, 0},
+ r = math.rad(60)
+ },
+ t = {1, 2, 3}
+}
+local ref2 = math3d.ref()
+ref2.v = math3d.vector(1, 2, 3, 4)
+print("ref1", ref1)
+print("ref1 value", math3d.tostring(math3d.matrix(ref1)))
+print(ref2)
+print("ref2 value", math3d.tostring(math3d.vector(ref2)))
+ref2.v = math3d.pack("dddd", 1, 2, 3, 4)
+print(ref2)
+ref2.v = math3d.vector(ref2, 1)
+print("ref2", ref2)
+
+for i = 1, 4 do
+ print("ref1 Line", i, math3d.tostring(ref1[i]))
+end
+
+for i = 1, 4 do
+ print("ref2 index", i, math3d.index(ref2, i))
+end
+
+print "===SRT==="
+ref1.m = {
+ s = 1,
+ r = {0, math.rad(60), 0},
+ t = {1, 2, 3}
+}
+print(ref1)
+local s, r, t = math3d.srt(ref1)
+print("S = ", math3d.tostring(s))
+print("R = ", math3d.tostring(r))
+print("T = ", math3d.tostring(t))
+
+local function print_srt()
+ print("S = ", math3d.tostring(ref1.s))
+ print("R = ", math3d.tostring(ref1.r))
+ print("T = ", math3d.tostring(ref1.t))
+end
+
+print_srt()
+ref1.s = 1
+print_srt()
+ref1.s = {3, 2, 1}
+print_srt()
+
+print "===QUAT==="
+
+local q = math3d.quaternion {0, math.rad(60, 0), 0}
+print(math3d.tostring(q))
+local ref3 = math3d.ref()
+ref3.m = math3d.quaternion {
+ axis = {1, 0, 0},
+ r = math.rad(60)
+} -- init mat with quat
+print(ref3)
+ref3.q = ref3 -- convert mat to quat
+print(ref3)
+
+print "===FUNC==="
+print(ref2)
+ref2.v = math3d.add(ref2, ref2, ref2)
+print(ref2)
+ref2.v = math3d.mul(ref2, 2.5)
+print("length", ref2, "=", math3d.length(ref2))
+print("floor", ref2, "=", math3d.tostring(math3d.floor(ref2)))
+print("dot", ref2, ref2, "=", math3d.dot(ref2, ref2))
+print("cross", ref2, ref2, "=", math3d.tostring(math3d.cross(ref2, ref2)))
+local point = math3d.vector(1, 2, 3, 1)
+print("transformH", ref1, point, "=", math3d.tostring(math3d.transformH(ref1, point)))
+print("normalize", ref2, "=", math3d.tostring(math3d.normalize(ref2)))
+print("normalize", ref3, "=", math3d.tostring(math3d.normalize(ref3)))
+print("transpose", ref1, "=", math3d.tostring(math3d.transpose(ref1)))
+print("inverse", ref1, "=", math3d.tostring(math3d.inverse(ref1)))
+print("inverse", ref2, "=", math3d.tostring(math3d.inverse(ref2)))
+print("inverse", ref3, "=", math3d.tostring(math3d.inverse(ref3)))
+print("reciprocal", ref2, "=", math3d.tostring(math3d.reciprocal(ref2)))
+
+print "===MULADD==="
+do
+ local v1, v2 = math3d.vector(1, 2, 3, 0), math3d.vector(1, 0, 0, 0)
+ local p = math3d.vector(4, 1, 0, 1)
+ local r = math3d.muladd(v1, v2, p)
+ print("muladd:", math3d.tostring(v1), math3d.tostring(v2), math3d.tostring(p), "=", math3d.tostring(r))
+end
+
+print "===VIEW&PROJECTION MATRIX==="
+do
+ local eyepos = math3d.vector {0, 5, -10}
+ local at = math3d.vector {0, 0, 0}
+ local direction = math3d.normalize(math3d.vector {1, 1, 1})
+ local updir = math3d.vector {0, 1, 0}
+
+ local mat1 = math3d.lookat(eyepos, at, updir)
+ local mat2 = math3d.lookto(eyepos, direction, updir)
+
+ print("lookat matrix:", math3d.tostring(mat1), "eyepos:", math3d.tostring(eyepos), "at:", math3d.tostring(at))
+
+ print("lookto matrix:", math3d.tostring(mat2), "eyepos:", math3d.tostring(eyepos), "direction:",
+ math3d.tostring(direction))
+
+ local frustum = {
+ l = -1,
+ r = 1,
+ t = -1,
+ b = 1,
+ n = 0.1,
+ f = 100
+ }
+
+ local perspective_mat = math3d.projmat(frustum)
+
+ local frustum_ortho = {
+ l = -1,
+ r = 1,
+ t = -1,
+ b = 1,
+ n = 0.1,
+ f = 100,
+ ortho = true
+ }
+ local ortho_mat = math3d.projmat(frustum_ortho)
+
+ print("perspective matrix:", math3d.tostring(perspective_mat))
+ print("ortho matrix:", math3d.tostring(ortho_mat))
+end
+
+print "===ROTATE VECTOR==="
+do
+ local v = math3d.vector {1, 2, 1}
+ local qq = math3d.quaternion {
+ axis = math3d.vector {0, 1, 0},
+ r = math.pi * 0.5
+ }
+ local vv = math3d.transform(qq, v, 0)
+ print("rotate vector with quaternion", math3d.tostring(v), "=", math3d.tostring(vv))
+
+ local mat = math3d.matrix {
+ s = 1,
+ r = q,
+ t = math3d.vector {0, 0, 0, 1}
+ }
+ local vv2 = math3d.transform(mat, v, 0)
+ print("transform vector with matrix", math3d.tostring(v), "=", math3d.tostring(vv2))
+
+ local p = math3d.vector {1, 2, 1, 1}
+ local mat2 = math3d.matrix {
+ s = 1,
+ r = q,
+ t = math3d.vector {0, 0, 5, 1}
+ }
+ local r_p = math3d.transform(mat2, p, nil)
+ print("transform point with matrix", math3d.tostring(p), "=", math3d.tostring(r_p))
+end
+
+print "===construct coordinate from forward vector==="
+do
+ local forward = math3d.normalize(math3d.vector {1, 1, 1})
+ local right, up = math3d.base_axes(forward)
+ print("forward:", math3d.tostring(forward), "right:", math3d.tostring(right), "up:", math3d.tostring(up))
+end
+
+print "===PROJ===="
+local projmat = math3d.projmat {
+ fov = 90,
+ aspect = 1,
+ n = 1,
+ f = 1000
+}
+print("PROJ", math3d.tostring(projmat))
+
+print "===ADAPTER==="
+local adapter = require "math3d.adapter"
+local testfunc = require "math3d.adapter.test"
+
+local vector = adapter.vector(testfunc.vector, 1) -- convert arguments to vector pointer from 1
+local matrix1 = adapter.matrix(testfunc.matrix1, 1, 1) -- convert 1 mat
+local matrix2 = adapter.matrix(testfunc.matrix2, 1, 2) -- convert 2 mat
+local matrix = adapter.matrix(testfunc.matrix2, 1) -- convert all mat
+local var = adapter.variant(testfunc.vector, testfunc.matrix1, 1)
+local format = adapter.format(testfunc.variant, testfunc.format, 2)
+local mvq = adapter.getter(testfunc.getmvq, "mvq") -- getmvq will return matrix, vector, quat
+local matrix2_v = adapter.format(testfunc.matrix2, "mm", 1)
+local retvec = adapter.output_vector(testfunc.retvec, 1)
+print(vector(ref2, math3d.vector {1, 2, 3}))
+print(matrix1(ref1))
+print(matrix2(ref1, ref1))
+print(matrix2_v(ref1, ref1))
+print(matrix(ref1, ref1))
+print(var(ref1))
+print(var(ref2))
+print(format("mv", ref1, ref2))
+local m, v, qv = mvq()
+print(math3d.tostring(m), math3d.tostring(v), math3d.tostring(qv))
+
+local v1, v2 = retvec()
+print(math3d.tostring(v1), math3d.tostring(v2))
+
diff --git a/framework/lualib-src/math3d/testadapter.c b/framework/lualib-src/math3d/testadapter.c
new file mode 100755
index 0000000..20c57e5
--- /dev/null
+++ b/framework/lualib-src/math3d/testadapter.c
@@ -0,0 +1,122 @@
+#define LUA_LIB
+
+#include
+#include
+
+static int
+lvector(lua_State *L) {
+ int top = lua_gettop(L);
+ int i,j;
+ luaL_checkstack(L, top * 4+1, NULL);
+ lua_pushstring(L, "VEC");
+ for (i=1;i<=top;i++) {
+ const float * vec4 = lua_touserdata(L, i);
+ for (j=0;j<4;j++) {
+ lua_pushnumber(L, vec4[j]);
+ }
+ }
+ return 4 * top + 1;
+}
+
+static int
+lmatrix1(lua_State *L) {
+ int i;
+ const float * mat = lua_touserdata(L, 1);
+ lua_pushstring(L, "MAT");
+ for (i=0;i<16;i++) {
+ lua_pushnumber(L, mat[i]);
+ }
+ return 17;
+}
+
+static int
+lmatrix2(lua_State *L) {
+ int i;
+ const float * mat1 = lua_touserdata(L, 1);
+ const float * mat2 = lua_touserdata(L, 2);
+ for (i=0;i<16;i++) {
+ lua_pushnumber(L, mat1[i] - mat2[i]);
+ }
+ return 16;
+}
+
+static int
+lformat(lua_State *L) {
+ const char * format = lua_tostring(L, 1);
+ lua_pushlightuserdata(L, (void *)format);
+ return 1;
+}
+
+static int
+lvariant(lua_State *L) {
+ size_t sz;
+ const char * format = lua_tolstring(L, 1, &sz);
+ int top = lua_gettop(L);
+ if (sz+1 != top) {
+ return luaL_error(L, "%s need %d arguments", format, (int)sz);
+ }
+ luaL_checkstack(L, sz, NULL);
+ int i;
+ for (i=2;i<=top;i++) {
+ const float * v = (const float *)lua_touserdata(L, i);
+ switch(format[i-2]) {
+ case 'm':
+ lua_pushnumber(L, v[15]);
+ break;
+ case 'v':
+ lua_pushnumber(L, v[0]);
+ break;
+ case 'q':
+ lua_pushnumber(L, v[3]);
+ break;
+ default:
+ return luaL_error(L, "Invalid format %s", format);
+ }
+ }
+
+ return sz;
+}
+
+static int
+lgetmvq(lua_State *L) {
+ float * mat = lua_touserdata(L, 1);
+ float * vec = lua_touserdata(L, 2);
+ float * quat = lua_touserdata(L, 3);
+ int i;
+ for (i=0;i<16;i++) {
+ mat[i] = (float)i;
+ }
+ for (i=0;i<4;i++) {
+ vec[i] = (float)i;
+ }
+ for (i=0;i<4;i++) {
+ quat[i] = 1.0f;
+ }
+ return 0;
+}
+
+static int
+lretvector(lua_State *L) {
+ static const float v1[4] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ static const float v2[4] = { 5.0f, 6.0f, 7.0f, 8.0f };
+ lua_pushlightuserdata(L, (void *)v1);
+ lua_pushlightuserdata(L, (void *)v2);
+ return 2;
+}
+
+LUAMOD_API int
+luaopen_math3d_adapter_test(lua_State *L) {
+ luaL_checkversion(L);
+ luaL_Reg l[] = {
+ { "vector", lvector },
+ { "matrix1", lmatrix1 },
+ { "matrix2", lmatrix2 },
+ { "format", lformat },
+ { "variant", lvariant },
+ { "getmvq", lgetmvq },
+ { "retvec", lretvector },
+ { NULL, NULL },
+ };
+ luaL_newlib(L, l);
+ return 1;
+}
diff --git a/framework/lualib-src/math3d/util.h b/framework/lualib-src/math3d/util.h
new file mode 100755
index 0000000..c784786
--- /dev/null
+++ b/framework/lualib-src/math3d/util.h
@@ -0,0 +1,27 @@
+#ifndef math3d_util_h
+#define math3d_util_h
+
+#include "glm/glm.hpp"
+#include "glm/gtc/constants.hpp"
+#include "glm/ext/scalar_constants.hpp"
+#include "glm/ext/scalar_relational.hpp"
+#include "glm/ext/vector_relational.hpp"
+
+template
+inline bool
+is_zero(const T& a, const T& e = T(glm::epsilon())) {
+ return glm::all(glm::equal(a, glm::zero(), e));
+}
+
+inline bool
+is_zero(const float& a, float e = glm::epsilon()) {
+ return glm::equal(a, glm::zero(), e);
+}
+
+template
+inline bool
+is_equal(const T& a, const T& b, const T& e = T(glm::epsilon())) {
+ return is_zero(a - b, e);
+}
+
+#endif //math3d_util_h
\ No newline at end of file