🐳 chore(工具): 增加 lua c toolkit
parent
b7815395e8
commit
4863ddbca7
@ -0,0 +1,30 @@
|
||||
# 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
|
||||
|
||||
@ -0,0 +1,552 @@
|
||||
# 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.
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -0,0 +1,528 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
#ifndef PLUGIN_H_
|
||||
#define PLUGIN_H_
|
||||
|
||||
#define PLUGIN "plugin_main"
|
||||
typedef int (*plugin)( void );
|
||||
|
||||
#endif /* PLUGIN_H_ */
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
#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;
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
#!/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
@ -0,0 +1,237 @@
|
||||
/* 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_ */
|
||||
@ -0,0 +1,183 @@
|
||||
/* 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_ */
|
||||
@ -0,0 +1,160 @@
|
||||
/* 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
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,165 +0,0 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local N = 1
|
||||
|
||||
local w = ecs.world()
|
||||
print("memory:", w:memory())
|
||||
|
||||
w:register{
|
||||
name = "vector",
|
||||
"x:float",
|
||||
"y:float",
|
||||
}
|
||||
|
||||
w:register{
|
||||
name = "mark",
|
||||
}
|
||||
|
||||
w:register{
|
||||
name = "id",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
w:register{
|
||||
name = "object",
|
||||
type = "lua",
|
||||
}
|
||||
|
||||
w:new{
|
||||
object = "Hello",
|
||||
}
|
||||
|
||||
local t = {}
|
||||
for i = 1, N do
|
||||
w:new{
|
||||
vector = {
|
||||
x = 1,
|
||||
y = 2,
|
||||
},
|
||||
}
|
||||
t[i] = {
|
||||
x = 1,
|
||||
y = 2,
|
||||
}
|
||||
end
|
||||
|
||||
w:update()
|
||||
|
||||
local function swap_c()
|
||||
for v in w:select "vector:update" do
|
||||
local vec = v.vector
|
||||
vec.x, vec.y = vec.y, vec.x
|
||||
end
|
||||
end
|
||||
|
||||
local function swap_lua()
|
||||
for _, v in ipairs(t) do
|
||||
v.x, v.y = v.y, v.x
|
||||
end
|
||||
end
|
||||
|
||||
local function timing(f)
|
||||
local c = os.clock()
|
||||
for i = 1, 100 do
|
||||
f()
|
||||
end
|
||||
return os.clock() - c
|
||||
end
|
||||
|
||||
print("memory:", w:memory())
|
||||
|
||||
print("CSWAP", timing(swap_c))
|
||||
print("LUASWAP", timing(swap_lua))
|
||||
|
||||
w:new{
|
||||
vector = {
|
||||
x = 3,
|
||||
y = 4,
|
||||
},
|
||||
id = 100,
|
||||
}
|
||||
|
||||
table.insert(t, {
|
||||
x = 3,
|
||||
y = 4,
|
||||
})
|
||||
|
||||
w:new{
|
||||
vector = {
|
||||
x = 5,
|
||||
y = 6,
|
||||
},
|
||||
mark = true,
|
||||
}
|
||||
|
||||
table.insert(t, {
|
||||
x = 5,
|
||||
y = 6,
|
||||
})
|
||||
|
||||
w:update()
|
||||
|
||||
local context = w:context{"vector", "mark", "id"}
|
||||
local test = require "ecs.ctest"
|
||||
local function csum()
|
||||
return test.sum(context)
|
||||
end
|
||||
print("csum = ", csum())
|
||||
|
||||
local function luasum()
|
||||
local s = 0
|
||||
for v in w:select "vector:in" do
|
||||
s = s + v.vector.x + v.vector.y
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
print("luasum = ", luasum())
|
||||
|
||||
local function luanativesum()
|
||||
local s = 0
|
||||
for _, v in ipairs(t) do
|
||||
s = s + v.x + v.y
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
print("lnative sum = ", luanativesum())
|
||||
|
||||
print("CSUM", timing(csum))
|
||||
print("LUASUM", timing(luasum))
|
||||
print("LNATIVESUM", timing(luanativesum))
|
||||
|
||||
print "vector:update"
|
||||
for v in w:select "vector:update" do
|
||||
local vec = v.vector
|
||||
print(vec.x, vec.y)
|
||||
vec.x, vec.y = vec.y, vec.x
|
||||
end
|
||||
|
||||
print "vector:in id?out"
|
||||
for v in w:select "vector:in id?out" do
|
||||
print(v.vector.x, v.vector.y, v.id)
|
||||
if v.id then
|
||||
v.id = 200
|
||||
end
|
||||
end
|
||||
|
||||
print "vector:in id:in"
|
||||
|
||||
for v in w:select "vector:in id:in" do
|
||||
print(v.vector.x, v.vector.y, v.id)
|
||||
end
|
||||
|
||||
print "object:update"
|
||||
|
||||
for v in w:select "object:update" do
|
||||
print(v.object)
|
||||
v.object = v.object .. " world"
|
||||
end
|
||||
|
||||
print "object:in"
|
||||
|
||||
for v in w:select "object:in" do
|
||||
print(v.object)
|
||||
end
|
||||
@ -0,0 +1,853 @@
|
||||
#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;
|
||||
}
|
||||
@ -0,0 +1,836 @@
|
||||
// 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
|
||||
@ -0,0 +1,835 @@
|
||||
// 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,338 @@
|
||||
#define LUA_LIB
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lua.h"
|
||||
|
||||
#define SKIPLIST_MAXLEVEL 32
|
||||
#define SKIPLIST_P 0.25
|
||||
|
||||
typedef struct skipsetNode {
|
||||
int64_t obj;
|
||||
struct skipsetNode *backward;
|
||||
struct skiplistLevel {
|
||||
struct skipsetNode *forward;
|
||||
unsigned int span;
|
||||
} level[];
|
||||
} skipsetNode;
|
||||
|
||||
typedef struct skipset {
|
||||
struct skipsetNode *header, *tail;
|
||||
unsigned long length;
|
||||
int level;
|
||||
} skipset;
|
||||
|
||||
static int slRandomLevel(void) {
|
||||
int level = 1;
|
||||
while ((random() & 0xffff) < (SKIPLIST_P * 0xffff))
|
||||
level += 1;
|
||||
return (level < SKIPLIST_MAXLEVEL) ? level : SKIPLIST_MAXLEVEL;
|
||||
}
|
||||
|
||||
static skipsetNode *slCreateNode(int level, int64_t obj) {
|
||||
skipsetNode *n = malloc(sizeof(*n) + level * sizeof(struct skiplistLevel));
|
||||
n->obj = obj;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int slInsert(skipset *sl, int64_t obj) {
|
||||
skipsetNode *update[SKIPLIST_MAXLEVEL], *x;
|
||||
unsigned int rank[SKIPLIST_MAXLEVEL];
|
||||
int i, level;
|
||||
|
||||
x = sl->header;
|
||||
for (i = sl->level - 1; i >= 0; i--) {
|
||||
rank[i] = i == (sl->level - 1) ? 0 : rank[i + 1];
|
||||
while (x->level[i].forward && x->level[i].forward->obj < obj) {
|
||||
rank[i] += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
x = x->level[0].forward;
|
||||
if (x && x->obj == obj)
|
||||
return 0;
|
||||
|
||||
level = slRandomLevel();
|
||||
if (level > sl->level) {
|
||||
for (i = sl->level; i < level; i++) {
|
||||
rank[i] = 0;
|
||||
update[i] = sl->header;
|
||||
update[i]->level[i].span = sl->length;
|
||||
}
|
||||
sl->level = level;
|
||||
}
|
||||
x = slCreateNode(level, obj);
|
||||
for (i = 0; i < level; i++) {
|
||||
x->level[i].forward = update[i]->level[i].forward;
|
||||
update[i]->level[i].forward = x;
|
||||
|
||||
x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
|
||||
update[i]->level[i].span = (rank[0] - rank[i]) + 1;
|
||||
}
|
||||
|
||||
for (i = level; i < sl->level; i++) {
|
||||
update[i]->level[i].span++;
|
||||
}
|
||||
|
||||
x->backward = (update[0] == sl->header) ? NULL : update[0];
|
||||
if (x->level[0].forward)
|
||||
x->level[0].forward->backward = x;
|
||||
else
|
||||
sl->tail = x;
|
||||
sl->length++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void slDeleteNode(skipset *sl, skipsetNode *x, skipsetNode **update) {
|
||||
int i;
|
||||
for (i = 0; i < sl->level; i++) {
|
||||
if (update[i]->level[i].forward == x) {
|
||||
update[i]->level[i].span += x->level[i].span - 1;
|
||||
update[i]->level[i].forward = x->level[i].forward;
|
||||
} else {
|
||||
update[i]->level[i].span -= 1;
|
||||
}
|
||||
}
|
||||
if (x->level[0].forward) {
|
||||
x->level[0].forward->backward = x->backward;
|
||||
} else {
|
||||
sl->tail = x->backward;
|
||||
}
|
||||
while (sl->level > 1 && sl->header->level[sl->level - 1].forward == NULL)
|
||||
sl->level--;
|
||||
sl->length--;
|
||||
}
|
||||
|
||||
static void slFreeNode(skipsetNode *node) {
|
||||
free(node);
|
||||
}
|
||||
|
||||
static int slDelete(skipset *sl, int64_t obj) {
|
||||
skipsetNode *update[SKIPLIST_MAXLEVEL], *x;
|
||||
int i;
|
||||
|
||||
x = sl->header;
|
||||
for (i = sl->level - 1; i >= 0; i--) {
|
||||
while (x->level[i].forward && x->level[i].forward->obj < obj)
|
||||
x = x->level[i].forward;
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
x = x->level[0].forward;
|
||||
if (x && (x->obj == obj)) {
|
||||
slDeleteNode(sl, x, update);
|
||||
slFreeNode(x);
|
||||
return 1;
|
||||
} else {
|
||||
return 0; /* not found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
static unsigned long slGetRank(skipset *sl, int64_t obj) {
|
||||
skipsetNode *x;
|
||||
unsigned long rank = 0;
|
||||
int i;
|
||||
|
||||
x = sl->header;
|
||||
for (i = sl->level - 1; i >= 0; i--) {
|
||||
while (x->level[i].forward && x->level[i].forward->obj <= obj) {
|
||||
rank += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
}
|
||||
if (x->obj && (x->obj == obj)) {
|
||||
return rank;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static skipsetNode *slGetNodeByRank(skipset *sl, unsigned long rank) {
|
||||
if (rank == 0 || rank > sl->length)
|
||||
return NULL;
|
||||
|
||||
skipsetNode *x;
|
||||
unsigned long traversed = 0;
|
||||
int i;
|
||||
|
||||
x = sl->header;
|
||||
for (i = sl->level - 1; i >= 0; i--) {
|
||||
while (x->level[i].forward && (traversed + x->level[i].span) <= rank) {
|
||||
traversed += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
}
|
||||
if (traversed == rank) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long slDeleteByRank(skipset *sl, unsigned int rank) {
|
||||
skipsetNode *update[SKIPLIST_MAXLEVEL], *x;
|
||||
unsigned long traversed = 0;
|
||||
int i;
|
||||
|
||||
x = sl->header;
|
||||
for (i = sl->level - 1; i >= 0; i--) {
|
||||
while (x->level[i].forward && (traversed + x->level[i].span) < rank) {
|
||||
traversed += x->level[i].span;
|
||||
x = x->level[i].forward;
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
x = x->level[0].forward;
|
||||
if (x) {
|
||||
slDeleteNode(sl, x, update);
|
||||
slFreeNode(x);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static skipset *slCreate(void) {
|
||||
int j;
|
||||
skipset *sl;
|
||||
|
||||
sl = malloc(sizeof(*sl));
|
||||
sl->level = 1;
|
||||
sl->length = 0;
|
||||
sl->header = slCreateNode(SKIPLIST_MAXLEVEL, 0);
|
||||
for (j = 0; j < SKIPLIST_MAXLEVEL; j++) {
|
||||
sl->header->level[j].forward = NULL;
|
||||
sl->header->level[j].span = 0;
|
||||
}
|
||||
sl->header->backward = NULL;
|
||||
sl->tail = NULL;
|
||||
return sl;
|
||||
}
|
||||
|
||||
static void slFree(skipset *sl) {
|
||||
skipsetNode *node = sl->header->level[0].forward, *next;
|
||||
free(sl->header);
|
||||
while (node) {
|
||||
next = node->level[0].forward;
|
||||
slFreeNode(node);
|
||||
node = next;
|
||||
}
|
||||
free(sl);
|
||||
}
|
||||
|
||||
static inline skipset *
|
||||
_to_skipset(lua_State *L, int idx) {
|
||||
skipset **sl = lua_touserdata(L, idx);
|
||||
if (sl == NULL) {
|
||||
luaL_error(L, "must be skipset object");
|
||||
}
|
||||
return *sl;
|
||||
}
|
||||
|
||||
static int
|
||||
_insert(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
lua_Integer obj = luaL_checkinteger(L, 2);
|
||||
lua_pushboolean(L, slInsert(sl, obj));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_delete(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
lua_Integer obj = luaL_checkinteger(L, 2);
|
||||
lua_pushboolean(L, slDelete(sl, obj));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_get_count(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
lua_pushinteger(L, sl->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_get_rank(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
lua_Integer obj = luaL_checkinteger(L, 2);
|
||||
|
||||
unsigned long rank = slGetRank(sl, obj);
|
||||
if (rank == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, rank);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_get_by_rank(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
unsigned long r1 = luaL_checkinteger(L, 2);
|
||||
|
||||
skipsetNode *node = slGetNodeByRank(sl, r1);
|
||||
if (node) {
|
||||
lua_pushinteger(L, node->obj);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_delete_by_rank(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
unsigned int rank = luaL_checkinteger(L, 2);
|
||||
lua_pushinteger(L, slDeleteByRank(sl, rank));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_new(lua_State *L) {
|
||||
skipset *psl = slCreate();
|
||||
|
||||
skipset **sl = (skipset **)lua_newuserdata(L, sizeof(skipset *));
|
||||
*sl = psl;
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_release(lua_State *L) {
|
||||
skipset *sl = _to_skipset(L, 1);
|
||||
slFree(sl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skipset_c(lua_State *L) {
|
||||
luaL_checkversion(L);
|
||||
|
||||
luaL_Reg l[] = {
|
||||
{ "insert", _insert },
|
||||
{ "delete", _delete },
|
||||
{ "delete_byrank", _delete_by_rank },
|
||||
|
||||
{ "count", _get_count },
|
||||
{ "rank", _get_rank },
|
||||
{ "byrank", _get_by_rank },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
lua_createtable(L, 0, 2);
|
||||
|
||||
luaL_newlib(L, l);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, _release);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
lua_pushcfunction(L, _get_count);
|
||||
lua_setfield(L, -2, "__len");
|
||||
|
||||
lua_pushcclosure(L, _new, 1);
|
||||
return 1;
|
||||
}
|
||||
@ -0,0 +1,326 @@
|
||||
local _M = {}
|
||||
local field_attrs = {"field", "type", "collation", "null", "key", "default", "extra", "comment", "the_index"}
|
||||
|
||||
local function showcolumn(ctx, tbl)
|
||||
local ret = {}
|
||||
local sqlret = assert(ctx.query(string.format("show full columns from %s", tbl)))
|
||||
for k, v in ipairs(sqlret) do
|
||||
local c = {}
|
||||
for _k, _v in pairs(v) do
|
||||
c[string.lower(_k)] = _v
|
||||
end
|
||||
c.the_index = tostring(k)
|
||||
for _, key in ipairs(field_attrs) do
|
||||
if c[key] == nil then
|
||||
c[key] = "__NULL__"
|
||||
end
|
||||
end
|
||||
table.insert(ret, c)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function showtables(ctx)
|
||||
local ret = {}
|
||||
local sqlret = assert(ctx.query("show tables;"))
|
||||
for _, v in ipairs(sqlret) do
|
||||
for _, value in pairs(v) do
|
||||
table.insert(ret, value)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function showcreatetable(ctx, tbl)
|
||||
local sqlret = assert(ctx.query(string.format("show create table %s", tbl)))
|
||||
local str = sqlret[1]["Create Table"]
|
||||
str = string.gsub(str, " AUTO_INCREMENT=%d*", "")
|
||||
str = string.gsub(str, " USING BTREE", "USING HASH")
|
||||
str = string.gsub(str, " ROW_FORMAT=DYNAMIC", "")
|
||||
str = string.gsub(str, " ROW_FORMAT=FIXED", "")
|
||||
str = string.gsub(str, " ROW_FORMAT=COMPACT", "")
|
||||
str = string.gsub(str, "ENGINE=%w*", "ENGINE=InnoDB")
|
||||
return str
|
||||
end
|
||||
|
||||
local function showindex(ctx, tbl)
|
||||
local ret = {}
|
||||
local sqlret = assert(ctx.query(string.format("show index from %s", tbl)))
|
||||
for _, v in ipairs(sqlret) do
|
||||
local c = {}
|
||||
for _k, _v in pairs(v) do
|
||||
c[string.lower(_k)] = _v
|
||||
end
|
||||
table.insert(ret, c)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function showcreateprocedure(ctx, proc)
|
||||
local sqlret = assert(ctx.query(string.format("show create procedure %s", proc)))
|
||||
local str = sqlret[1]["Create Procedure"]
|
||||
str = string.gsub(str, "CREATE(.*)PROCEDURE", "CREATE PROCEDURE")
|
||||
-- str=string.format("DROP PROCEDURE IF EXISTS `%s`;\nDELIMITER $$\n%s\n$$\nDELIMITER ;",proc,str)
|
||||
return str
|
||||
end
|
||||
|
||||
local function showcreatefunction(ctx, proc)
|
||||
local sqlret = assert(ctx.query(string.format("show create function %s", proc)))
|
||||
local str = sqlret[1]["Create Function"]
|
||||
str = string.gsub(str, "CREATE(.*)FUNCTION", "CREATE FUNCTION")
|
||||
-- str=string.format("DROP PROCEDURE IF EXISTS `%s`;\nDELIMITER $$\n%s\n$$\nDELIMITER ;",proc,str)
|
||||
return str
|
||||
end
|
||||
|
||||
local function showdatabase(ctx)
|
||||
local sqlret = assert(ctx.query("select database()"))
|
||||
return sqlret[1]["database()"]
|
||||
end
|
||||
|
||||
local function showprocedures(ctx)
|
||||
local dbname = showdatabase(ctx)
|
||||
local sqlret = assert(ctx.query(string.format("select name,type from mysql.proc where db='%s'", dbname)))
|
||||
local ret, func = {}, {}
|
||||
for _, v in pairs(sqlret) do
|
||||
local name, type = v.name, v.type
|
||||
if type == 'PROCEDURE' then
|
||||
table.insert(ret, name);
|
||||
else
|
||||
table.insert(func, name)
|
||||
end
|
||||
end
|
||||
return ret, func
|
||||
end
|
||||
|
||||
function _M.newctx(ret, opt)
|
||||
ret.query = assert(opt.query)
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.load(ctx)
|
||||
ctx.table_list = showtables(ctx)
|
||||
ctx.table = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = showcolumn(ctx, k)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.tablecreate = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = showcreatetable(ctx, k)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.index = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = showindex(ctx, k)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
local proc, func = showprocedures(ctx)
|
||||
ctx.proc_list = proc
|
||||
ctx.proc = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = showcreateprocedure(ctx, k)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.func_list = func
|
||||
ctx.func = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = showcreatefunction(ctx, k)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
return ctx
|
||||
end
|
||||
|
||||
local function array2dict(array)
|
||||
local d = {}
|
||||
for k, v in ipairs(array) do
|
||||
d[v] = k
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
local function fieldfind(tbl, k)
|
||||
for _, v in pairs(tbl) do
|
||||
if v.field == k then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function markfield(set, tbl, v)
|
||||
local null = ""
|
||||
local default = ""
|
||||
if v.null == "NO" then
|
||||
null = "NOT NULL"
|
||||
end
|
||||
if v.default == "__NULL__" then
|
||||
if v.null ~= "NO" then
|
||||
default = "DEFAULT NULL"
|
||||
end
|
||||
else
|
||||
default = string.format("DEFAULT '%s'", v.default)
|
||||
end
|
||||
local collate = ""
|
||||
if v.collation ~= "" and v.collation ~= "__NULL__" then
|
||||
collate = string.format("COLLATE '%s'", v.collation)
|
||||
end
|
||||
local cmt = ""
|
||||
if v.comment ~= "" then
|
||||
cmt = string.format("COMMENT '%s'", v.comment)
|
||||
end
|
||||
local pos = 'FIRST'
|
||||
if tonumber(v.the_index) > 1 then
|
||||
pos = string.format("ALTER `%s`", set[v.the_index - 1].field)
|
||||
end
|
||||
return null, default, cmt, collate, pos
|
||||
end
|
||||
|
||||
local function make_changefield(set, tbl, v)
|
||||
local null, default, cmt, collate, pos = markfield(set, tbl, v)
|
||||
return string.format("alter table `%s` change column `%s` `%s` %s %s %s %s %s %s %s", tbl, v.field, v.field,
|
||||
string.lower(v.type), null, default, cmt, collate, string.lower(v.extra or ""), pos)
|
||||
end
|
||||
|
||||
local function make_addfield(set, tbl, v)
|
||||
local null, default, cmt, collate, pos = markfield(set, tbl, v)
|
||||
return string.format("alter table `%s` add column `%s` %s %s %s %s %s %s %s", tbl, v.field, string.lower(v.type),
|
||||
null, default, cmt, collate, string.lower(v.extra or ""), pos)
|
||||
end
|
||||
|
||||
local function tablefield_compare(l, r)
|
||||
if l == r then
|
||||
return true
|
||||
end
|
||||
assert(l.field == r.field)
|
||||
for _, k in ipairs(field_attrs) do
|
||||
if k ~= "key" and l[k] ~= r[k] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function fields_re_index(tbl)
|
||||
for k, v in ipairs(tbl) do
|
||||
v.the_index = tostring(k)
|
||||
end
|
||||
end
|
||||
|
||||
local function compare_fields(ret, name, lfields, rfields)
|
||||
while true do
|
||||
local over = true
|
||||
for k, lfield in ipairs(lfields) do
|
||||
local rfield = fieldfind(rfields, lfield.field)
|
||||
if not rfield then
|
||||
table.insert(ret, string.format("alter table `%s` drop column `%s`", name, lfield.field))
|
||||
table.remove(lfields, k)
|
||||
over = false
|
||||
break
|
||||
end
|
||||
end
|
||||
fields_re_index(lfields)
|
||||
if over then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
local over = true
|
||||
for k, rfield in ipairs(rfields) do
|
||||
local lfield = fieldfind(lfields, rfield.field)
|
||||
if not lfield then
|
||||
table.insert(ret, make_addfield(lfields, k, rfield))
|
||||
elseif not tablefield_compare(lfield, rfield) then
|
||||
table.insert(ret, make_changefield(lfields, k, rfield))
|
||||
end
|
||||
end
|
||||
fields_re_index(lfields)
|
||||
if over then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function gensql(left, right)
|
||||
local sdict = array2dict(left.table_list)
|
||||
local cdict = array2dict(right.table_list)
|
||||
local ret = {}
|
||||
for k in pairs(sdict) do
|
||||
if not cdict[k] then
|
||||
table.insert(ret, (string.format("drop table if exists `%s`", k)))
|
||||
else
|
||||
local stbl = left.table[k]
|
||||
local ctbl = right.table[k]
|
||||
compare_fields(ret, k, stbl, ctbl)
|
||||
end
|
||||
end
|
||||
for k in pairs(cdict) do
|
||||
if not sdict[k] then
|
||||
table.insert(ret, right.tablecreate[k])
|
||||
end
|
||||
end
|
||||
|
||||
local sdict = array2dict(left.proc_list)
|
||||
local cdict = array2dict(right.proc_list)
|
||||
|
||||
for k in pairs(sdict) do
|
||||
if not cdict[k] then
|
||||
table.insert(ret, (string.format("drop procedure if exists `%s`", k)))
|
||||
else
|
||||
local sproc = left.proc[k]
|
||||
local cproc = right.proc[k]
|
||||
if sproc ~= cproc then
|
||||
table.insert(ret, (string.format("drop procedure if exists `%s`", k)))
|
||||
table.insert(ret, cproc)
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(cdict) do
|
||||
if not sdict[k] then
|
||||
table.insert(ret, right.proc[k])
|
||||
end
|
||||
end
|
||||
|
||||
local sdict = array2dict(left.func_list)
|
||||
local cdict = array2dict(right.func_list)
|
||||
for k in pairs(sdict) do
|
||||
if not cdict[k] then
|
||||
table.insert(ret, (string.format("drop function if exists `%s`", k)))
|
||||
else
|
||||
local sfunc = left.func[k]
|
||||
local cfunc = right.func[k]
|
||||
if sfunc ~= cfunc then
|
||||
table.insert(ret, (string.format("drop function if exists `%s`", k)))
|
||||
table.insert(ret, cfunc)
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(cdict) do
|
||||
if not sdict[k] then
|
||||
table.insert(ret, right.func[k])
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.save(ctx)
|
||||
local left = _M.newctx({}, ctx)
|
||||
_M.load(left)
|
||||
|
||||
local ret = gensql(left, ctx)
|
||||
|
||||
for _, v in ipairs(ret) do
|
||||
left.query(v)
|
||||
end
|
||||
end
|
||||
|
||||
return _M
|
||||
@ -0,0 +1,162 @@
|
||||
local _M = {}
|
||||
|
||||
local function getfile(ctx, f)
|
||||
return string.format("%s/%s.%s", ctx.dir, ctx.name, f)
|
||||
end
|
||||
|
||||
local function writefile(name, str)
|
||||
local file = assert(io.open(name, "w"))
|
||||
file:write(str)
|
||||
file:close()
|
||||
end
|
||||
|
||||
local function readfile(name)
|
||||
local file = assert(io.open(name, "r"))
|
||||
local str = file:read("*a")
|
||||
file:close()
|
||||
return str
|
||||
end
|
||||
|
||||
local function readfilelines(name)
|
||||
local file = assert(io.open(name, "r"))
|
||||
local ret = {}
|
||||
while true do
|
||||
local line = file:read("*l")
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
table.insert(ret, line)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function encode_table_column(ret, attrs)
|
||||
local function encode_column(lines)
|
||||
local ret = {}
|
||||
for _, k in ipairs(attrs) do
|
||||
local v = lines[k]
|
||||
if v then
|
||||
table.insert(ret, string.format("%s='%s'", k, v))
|
||||
end
|
||||
end
|
||||
return (table.concat(ret, " "))
|
||||
end
|
||||
local tbl = {}
|
||||
for _, v in ipairs(ret) do
|
||||
table.insert(tbl, encode_column(v))
|
||||
end
|
||||
return (table.concat(tbl, "\n"))
|
||||
end
|
||||
|
||||
local function decode_table_column(tbls)
|
||||
local function decode_column(linestr)
|
||||
local ret = {}
|
||||
for k, v in string.gmatch(linestr, "(%S+)='(.-)'") do
|
||||
ret[k] = v
|
||||
end
|
||||
return ret
|
||||
end
|
||||
local ret = {}
|
||||
for _, v in pairs(tbls) do
|
||||
local r = decode_column(v)
|
||||
table.insert(ret, r)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function decode_table_index(tbls)
|
||||
local function decode_column(linestr)
|
||||
local ret = {}
|
||||
for k, v in string.gmatch(linestr, "(%S+)='(.-)'") do
|
||||
ret[k] = v
|
||||
end
|
||||
return ret
|
||||
end
|
||||
local ret = {}
|
||||
for _, v in pairs(tbls) do
|
||||
local r = decode_column(v)
|
||||
local old = ret[r.key_name]
|
||||
if old then
|
||||
old.column_name = old.column_name .. ',' .. r.column_name
|
||||
else
|
||||
ret[r.key_name] = r
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.load(ctx)
|
||||
ctx.table_list = readfilelines(getfile(ctx, "table.list"))
|
||||
ctx.table = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local str = readfilelines(getfile(ctx, "table." .. k))
|
||||
local r = decode_table_column(str)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.tablecreate = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = readfile(getfile(ctx, "tablecreate." .. k))
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.index = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local str = readfilelines(getfile(ctx, "index." .. k))
|
||||
local r = decode_table_index(str)
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.proc_list = readfilelines(getfile(ctx, "proc.list"))
|
||||
ctx.proc = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = readfile(getfile(ctx, "proc." .. k))
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
ctx.func_list = readfilelines(getfile(ctx, "func.list"))
|
||||
ctx.func = setmetatable({}, {
|
||||
__index = function(t, k)
|
||||
local r = readfile(getfile(ctx, "func." .. k))
|
||||
t[k] = r
|
||||
return r
|
||||
end,
|
||||
})
|
||||
return ctx
|
||||
end
|
||||
|
||||
function _M.newctx(ret, opt)
|
||||
ret.name = assert(opt.name)
|
||||
ret.dir = assert(opt.dir)
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.compare(ctx, new)
|
||||
return new
|
||||
end
|
||||
|
||||
local index_field_attrs = {"table", "non_unique", "key_name", "seq_in_index", "column_name", "collation", "sub_part",
|
||||
"packed", "null", "index_type", "the_index", "comment"}
|
||||
local field_attrs = {"field", "type", "collation", "null", "key", "default", "extra", "comment", "the_index"}
|
||||
function _M.save(ctx)
|
||||
writefile(getfile(ctx, "table.list"), table.concat(ctx.table_list, "\n"))
|
||||
for _, k in ipairs(ctx.table_list) do
|
||||
writefile(getfile(ctx, "table." .. k), encode_table_column(ctx.table[k], field_attrs))
|
||||
writefile(getfile(ctx, "index." .. k), encode_table_column(ctx.index[k], index_field_attrs))
|
||||
writefile(getfile(ctx, "tablecreate." .. k), ctx.tablecreate[k])
|
||||
end
|
||||
writefile(getfile(ctx, "proc.list"), table.concat(ctx.proc_list, "\n"))
|
||||
for _, k in ipairs(ctx.proc_list) do
|
||||
writefile(getfile(ctx, "proc." .. k), ctx.proc[k])
|
||||
end
|
||||
writefile(getfile(ctx, "func.list"), table.concat(ctx.func_list, "\n"))
|
||||
for _, k in ipairs(ctx.func_list) do
|
||||
writefile(getfile(ctx, "func." .. k), ctx.func[k])
|
||||
end
|
||||
end
|
||||
|
||||
return _M
|
||||
@ -0,0 +1,28 @@
|
||||
-- mysql结构同步的lua库实现
|
||||
|
||||
local _M = {}
|
||||
|
||||
_M.db = require "mysqlauto.db"
|
||||
_M.file = require "mysqlauto.file"
|
||||
|
||||
function _M.newctx(opt)
|
||||
assert(opt.name)
|
||||
assert(opt.query)
|
||||
assert(opt.dir)
|
||||
local ret = {}
|
||||
_M.db.newctx(ret, opt)
|
||||
_M.file.newctx(ret, opt)
|
||||
return ret
|
||||
end
|
||||
|
||||
function _M.db2file(ctx)
|
||||
_M.db.load(ctx)
|
||||
_M.file.save(ctx)
|
||||
end
|
||||
|
||||
function _M.file2db(ctx)
|
||||
_M.file.load(ctx)
|
||||
_M.db.save(ctx)
|
||||
end
|
||||
|
||||
return _M
|
||||
@ -1,41 +0,0 @@
|
||||
local skynet = require "skynet"
|
||||
local mc = require "skynet.multicast"
|
||||
local st = require "skynet.sharetable"
|
||||
|
||||
local shared
|
||||
local channel
|
||||
|
||||
local M
|
||||
|
||||
local function init()
|
||||
assert(not shared)
|
||||
assert(not channel)
|
||||
shared = skynet.uniqueservice "shared"
|
||||
local name = skynet.call(shared, "lua", "channel")
|
||||
channel = mc.new {
|
||||
channel = name,
|
||||
dispatch = function(_, _, filenames)
|
||||
for _, filename in pairs(filenames) do
|
||||
if M[filename] then
|
||||
M[filename] = nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
M = setmetatable({}, {
|
||||
__index = function(self, filename)
|
||||
if not shared then
|
||||
init()
|
||||
end
|
||||
|
||||
local obj = st.query(filename)
|
||||
if obj then
|
||||
self[filename] = obj
|
||||
end
|
||||
return obj
|
||||
end,
|
||||
})
|
||||
|
||||
return M
|
||||
@ -1,78 +0,0 @@
|
||||
local skynet = require "skynet"
|
||||
local queue = require "skynet.queue"
|
||||
local util = require "store_util"
|
||||
require "skynet.manager"
|
||||
|
||||
local dbconf
|
||||
local lock = queue()
|
||||
local guid_generator_addrs = {}
|
||||
|
||||
local CMD = {}
|
||||
|
||||
function CMD.init(conf)
|
||||
assert(not dbconf, "dbmgr has been initialized.")
|
||||
dbconf = conf -- init is allowed only once
|
||||
|
||||
local uidconf = dbconf.guid_generator
|
||||
assert(uidconf)
|
||||
for _, worker_id in pairs(uidconf.worker_ids) do
|
||||
local addr = skynet.newservice("guid_generator", worker_id)
|
||||
table.insert(guid_generator_addrs, addr)
|
||||
end
|
||||
|
||||
local redisconf = dbconf.redis
|
||||
for dbkey, conf in pairs(redisconf) do
|
||||
for index = 1, conf.service_num do
|
||||
local addr = skynet.newservice("redisd", dbkey, index)
|
||||
local ok = skynet.call(addr, "lua", "init", conf)
|
||||
if not ok then
|
||||
assert(false, ("redisd init failed. [dbkey] %s [id] %d"):format(dbkey, index))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local mysqlconf = dbconf.mysql
|
||||
for dbkey, conf in pairs(mysqlconf) do
|
||||
for index = 1, conf.service_num do
|
||||
local addr = skynet.newservice("mysqld", dbkey, index)
|
||||
local ok = skynet.call(addr, "lua", "init", conf)
|
||||
if not ok then
|
||||
assert(false, ("mysqld init failed. [dbkey] %s [id] %d"):format(dbkey, index))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function CMD.mysql_service_num(dbkey)
|
||||
if not dbconf then return end
|
||||
local mysqlconf = dbconf.mysql
|
||||
if not mysqlconf then return end
|
||||
local conf = mysqlconf[dbkey]
|
||||
if not conf then return end
|
||||
return conf.service_num
|
||||
end
|
||||
|
||||
function CMD.redis_service_num(dbkey)
|
||||
if not dbconf then return end
|
||||
local redisconf = dbconf.redis
|
||||
if not redisconf then return end
|
||||
local conf = redisconf[dbkey]
|
||||
if not conf then return end
|
||||
return conf.service_num
|
||||
end
|
||||
|
||||
function CMD.guid_generators()
|
||||
return guid_generator_addrs
|
||||
end
|
||||
|
||||
skynet.start(function()
|
||||
skynet.dispatch("lua", function(_, _, cmd, ...)
|
||||
local f = CMD[cmd]
|
||||
assert(f, cmd)
|
||||
skynet.retpack(f(...))
|
||||
end)
|
||||
end)
|
||||
|
||||
skynet.register(".dbmgr")
|
||||
@ -1,50 +0,0 @@
|
||||
local skynet = require "skynet"
|
||||
local mysql = require "skynet.db.mysql"
|
||||
local util = require "store_util"
|
||||
require "skynet.manager"
|
||||
|
||||
local traceback = debug.traceback
|
||||
|
||||
local dbkey, index = ...
|
||||
local db
|
||||
|
||||
local CMD = {}
|
||||
|
||||
local function success(ret)
|
||||
if not ret or ret.err or ret.badresult then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function CMD.init(conf)
|
||||
db = mysql.connect(conf)
|
||||
db:query("set names utf8mb4")
|
||||
return true
|
||||
end
|
||||
|
||||
function CMD.exec_one(sql)
|
||||
local ok, ret = xpcall(db.query, traceback, db, sql)
|
||||
if not ok or not success(ret) then
|
||||
assert(false, ("sql=[%s] ret=[%s]"):format(sql, util.encode(ret)))
|
||||
return
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function CMD.exec(sqls)
|
||||
for i = 1, #sqls do
|
||||
local sql = sqls[i]
|
||||
CMD.exec_one(sql)
|
||||
end
|
||||
end
|
||||
|
||||
skynet.start(function()
|
||||
skynet.dispatch("lua", function(_, _, cmd, ...)
|
||||
local f = CMD[cmd]
|
||||
assert(f, cmd)
|
||||
skynet.retpack(f(...))
|
||||
end)
|
||||
end)
|
||||
|
||||
skynet.register(util.mysql_sname(dbkey, index))
|
||||
@ -1,42 +0,0 @@
|
||||
local skynet = require "skynet"
|
||||
local redis = require "skynet.db.redis"
|
||||
local util = require "store_util"
|
||||
require "skynet.manager"
|
||||
|
||||
local traceback = debug.traceback
|
||||
local tunpack = table.unpack
|
||||
local tconcat = table.concat
|
||||
local dbkey, index = ...
|
||||
local db
|
||||
|
||||
local CMD = {}
|
||||
|
||||
function CMD.init(conf)
|
||||
db = redis.connect(conf)
|
||||
return true
|
||||
end
|
||||
|
||||
function CMD.exec_one(cmd, ...)
|
||||
local ok, ret = xpcall(db[cmd], traceback, db, ...)
|
||||
if not ok then
|
||||
assert(false, ("cmd=[%s %s] ret=[%s]"):format(cmd, tconcat({...}, " "), ret))
|
||||
return
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function CMD.exec(cmds)
|
||||
for _, cmd in pairs(cmds) do
|
||||
xpcall(CMD.exec_one, traceback, tunpack(cmd))
|
||||
end
|
||||
end
|
||||
|
||||
skynet.start(function()
|
||||
skynet.dispatch("lua", function(_, _, cmd, ...)
|
||||
local f = CMD[cmd]
|
||||
assert(f, cmd)
|
||||
skynet.retpack(f(...))
|
||||
end)
|
||||
end)
|
||||
|
||||
skynet.register(util.redis_sname(dbkey, index))
|
||||
Loading…
Reference in New Issue