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