🐳 chore(工具): 增加 math3d

develop
cloudfreexiao 5 years ago
parent 4863ddbca7
commit 37a18517ee

9
.gitmodules vendored

@ -4,3 +4,12 @@
[submodule "framework/3rd/goscon"] [submodule "framework/3rd/goscon"]
path = framework/3rd/goscon path = framework/3rd/goscon
url = https://github.com/cloudfreexiao/goscon.git 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

@ -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
...

@ -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

@ -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)
--------------------------------------------------------------------------
<a href="http://opensource.org/licenses/BSD-2-Clause" target="_blank">
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
</a>
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.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,40 @@
#include <stdio.h>
#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;
}

@ -0,0 +1 @@
Subproject commit 70a061109d8f9ba36442c27fafc2f6e6c8c7af99

@ -0,0 +1 @@
Subproject commit 84f2045a79a4aa2454801a98e2de0401bd9c8aee

@ -0,0 +1 @@
Subproject commit 7f1f94b66762df19570505219c9031f9a411c649

@ -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

@ -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.

@ -1,22 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#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;
}

@ -1,54 +0,0 @@
#include <lua.h>
#include <lauxlib.h>
#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;
}

@ -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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <lua.h>
#include <lauxlib.h>
#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;
}

@ -1,23 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#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;
}

@ -1,8 +0,0 @@
#ifndef PLUGIN_H_
#define PLUGIN_H_
#define PLUGIN "plugin_main"
typedef int (*plugin)( void );
#endif /* PLUGIN_H_ */

@ -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;
}

@ -1,23 +0,0 @@
#include <lua.h>
#include <lauxlib.h>
#include <stddef.h>
#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;
}

@ -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

File diff suppressed because it is too large Load Diff

@ -1,237 +0,0 @@
/* Copyright 2013-2016 Philipp Janda <siffiejoe@gmx.net>
*
* 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 <stddef.h>
#if defined(__cplusplus) && !defined(MOON_LUA_CPP)
extern "C"
{
#endif
#include <lua.h>
#include <lauxlib.h>
#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_ */

@ -1,183 +0,0 @@
/* Copyright 2013-2016 Philipp Janda <siffiejoe@gmx.net>
*
* 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 <stdio.h>
#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 <unistd.h>
/* check for minimum POSIX version that specifies dlopen etc. */
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || \
defined(HAVE_DLFCN_H)
#include <dlfcn.h>
/* 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 <link.h>
#endif /* Linux with dl_iterate_phdr() function */
#if defined(__FreeBSD__) || defined(__DragonFly__) || \
defined(__NetBSD__) || defined(__OpenBSD__)
#define MOON_DLFIX_DL_ITERATE_PHDR
#include <link.h>
#endif /* BSDs with dl_iterate_phdr() function */
#if !defined(MOON_DLFIX_FIND) && \
defined(MOON_DLFIX_DL_ITERATE_PHDR)
#include <string.h>
#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_ */

@ -1,160 +0,0 @@
/* Copyright 2013-2015 Philipp Janda <siffiejoe@gmx.net>
*
* 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

@ -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

@ -1,853 +0,0 @@
#include "math3d-left.h"
#include <lua.h>
#include <lauxlib.h>
// 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;
}

@ -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 <math.h>
#include <float.h>
#include <stddef.h>
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 <stdio.h>
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

@ -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 <math.h>
#include <float.h>
#include <stddef.h>
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

@ -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

@ -0,0 +1,23 @@
#ifndef math_fastcall_h
#define math_fastcall_h
#include <lua.h>
#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

@ -0,0 +1,808 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#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;i<B->cap;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;i<n-1;i++) {
printf("%.3g ", address[i]);
}
printf("%.3g",address[i]);
}
static void
print_object(const float *address, int id, int type) {
switch(type) {
case LINEAR_TYPE_NONE:
printf("(None");
break;
case LINEAR_TYPE_MAT:
printf("(M%d: ",id);
print_float(address, 16);
break;
case LINEAR_TYPE_VEC4:
printf("(V%d: ",id);
print_float(address, 4);
break;
case LINEAR_TYPE_QUAT:
printf("(Q%d: ",id);
print_float(address, 4);
break;
default:
printf("(Invalid");
break;
}
printf(")");
}
void
lastack_print(struct lastack *LS) {
printf("version = %d\n", LS->version);
printf("stack %d/%d:\n", LS->stack_top, LS->stack_cap);
int i;
for (i=0;i<LS->stack_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<from;i++) {
printf(".");
}
}
}
int
lastack_type(struct lastack *LS, int64_t id) {
union stackid sid;
sid.i = id;
return sid.s.type;
}
char *
lastack_idstring(int64_t id, char tmp[64]) {
union stackid sid;
sid.i = id;
char flags[3] = { 0,0,0 };
switch(sid.s.type) {
case LINEAR_TYPE_MAT:
flags[0] = 'M';
break;
case LINEAR_TYPE_VEC4:
flags[0] = 'V';
break;
case LINEAR_TYPE_QUAT:
flags[0] = 'Q';
break;
default:
flags[0] = '?';
break;
}
if (sid.s.persistent) {
flags[1] = 'P';
}
snprintf(tmp, 64, "id=%d version=%d %s",sid.s.id, sid.s.version, flags);
return tmp;
}
#if 0
int
test_main() {
struct lastack *LS = lastack_new();
float v[4] = { 1,2,3,4 };
float m[16] = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
};
lastack_pushvector(LS, v, LINEAR_TYPE_VEC4);
int64_t c = lastack_mark(LS);
lastack_pushmatrix(LS, m);
lastack_pushref(LS, -c);
lastack_dup(LS);
lastack_print(LS);
lastack_reset(LS);
lastack_pushref(LS, c);
lastack_dup(LS);
lastack_dup(LS);
lastack_dup(LS);
lastack_dup(LS);
lastack_dup(LS);
lastack_dup(LS);
lastack_print(LS);
lastack_reset(LS);
lastack_print(LS);
lastack_delete(LS);
return 0;
}
#endif

@ -0,0 +1,53 @@
#ifndef linear_algebra_h
#define linear_algebra_h
#include <stddef.h>
#include <stdint.h>
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

File diff suppressed because it is too large Load Diff

@ -0,0 +1,24 @@
#ifndef math3d_lua_binding_h
#define math3d_lua_binding_h
#include "linalg.h"
#include <lua.h>
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

@ -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

@ -0,0 +1,538 @@
#define LUA_LIB
#include <lua.h>
#include <lauxlib.h>
#include <stdint.h>
#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;
}

@ -0,0 +1,412 @@
#define LUA_LIB
#define GLM_ENABLE_EXPERIMENTAL
#include <cmath>
extern "C" {
#include "linalg.h"
#include "math3dfunc.h"
}
#include "util.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/ext/scalar_relational.hpp>
#include <glm/ext/vector_relational.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/ext/vector_common.hpp>
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]);
}
}

@ -0,0 +1,107 @@
#ifndef linear_algebra_refstack_h
#define linear_algebra_refstack_h
#include <lua.h>
#include <lauxlib.h>
#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

@ -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))

@ -0,0 +1,122 @@
#define LUA_LIB
#include <lua.h>
#include <lauxlib.h>
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;
}

@ -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<typename T>
inline bool
is_zero(const T& a, const T& e = T(glm::epsilon<float>())) {
return glm::all(glm::equal(a, glm::zero<T>(), e));
}
inline bool
is_zero(const float& a, float e = glm::epsilon<float>()) {
return glm::equal(a, glm::zero<float>(), e);
}
template<typename T>
inline bool
is_equal(const T& a, const T& b, const T& e = T(glm::epsilon<float>())) {
return is_zero(a - b, e);
}
#endif //math3d_util_h
Loading…
Cancel
Save