🐳 chore(工具): 增加 math3d
parent
4863ddbca7
commit
37a18517ee
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: 'false'
|
||||||
|
AlignConsecutiveDeclarations: 'false'
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignTrailingComments: 'true'
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||||
|
AllowShortBlocksOnASingleLine: 'false'
|
||||||
|
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||||
|
AllowShortFunctionsOnASingleLine: 'false'
|
||||||
|
AllowShortIfStatementsOnASingleLine: 'false'
|
||||||
|
AllowShortLoopsOnASingleLine: 'false'
|
||||||
|
AlwaysBreakBeforeMultilineStrings: 'true'
|
||||||
|
AlwaysBreakTemplateDeclarations: 'true'
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
Cpp11BracedListStyle: 'false'
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IndentCaseLabels: 'false'
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentWidth: '4'
|
||||||
|
IndentWrappedFunctionNames: 'true'
|
||||||
|
Language: Cpp
|
||||||
|
MaxEmptyLinesToKeep: '2'
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
PointerAlignment: Left
|
||||||
|
SpaceBeforeAssignmentOperators: 'true'
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: 'false'
|
||||||
|
SpacesBeforeTrailingComments: '4'
|
||||||
|
SpacesInCStyleCastParentheses: 'false'
|
||||||
|
SpacesInContainerLiterals: 'false'
|
||||||
|
SpacesInParentheses: 'false'
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: '4'
|
||||||
|
UseTab: Never
|
||||||
|
|
||||||
|
...
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
# External junk
|
||||||
|
.DS_Store
|
||||||
|
_ReSharper*
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.dir
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.bak
|
||||||
|
Win32
|
||||||
|
Win64
|
||||||
|
Debug
|
||||||
|
Release
|
||||||
|
Profile
|
||||||
|
Development
|
||||||
|
Obj
|
||||||
|
Bin
|
||||||
|
Lib
|
||||||
|
.tags
|
||||||
|
.tags_sorted_by_file
|
||||||
|
*.lnk
|
||||||
|
ipch
|
||||||
|
__pycache__
|
||||||
|
Thumbs.db
|
||||||
|
.build*
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
/build
|
||||||
|
/build-*
|
||||||
|
/captures
|
||||||
|
|
||||||
|
# assets
|
||||||
|
assets/shaders/*
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin
|
||||||
|
docs/Doxyfile
|
||||||
|
docs/html
|
||||||
|
docs/warnings.txt
|
||||||
|
imgui.ini
|
||||||
|
install
|
||||||
|
*.log
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
shaders_h
|
||||||
|
src/rizz/plugin_bundle.h
|
||||||
|
src/rizz/plugin_bundle_native.h
|
||||||
|
android
|
||||||
|
assets-db.json
|
||||||
|
compile_commands.json
|
||||||
|
examples/assets/shaders/**
|
||||||
|
|
||||||
|
# temp
|
||||||
|
scripts/generators/fake_libc_include
|
||||||
|
temp
|
||||||
|
|
||||||
|
# Compiled binaries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.exe
|
||||||
|
.build
|
||||||
|
*.fso
|
||||||
|
*.vso
|
||||||
|
*.pyc
|
||||||
|
*.obj
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
## dmon
|
||||||
|
[@septag](https://twitter.com/septagh)
|
||||||
|
|
||||||
|
_dmon_ is a tiny C library that monitors changes in a directory.
|
||||||
|
It provides a unified solution to multiple system APIs that exist for each OS. It can also monitor directories recursively.
|
||||||
|
|
||||||
|
### Platforms
|
||||||
|
- Windows: `ReadDirectoryChangesW` backend. Tested with Windows10 SDK + Visual Studio 2019
|
||||||
|
- Linux: `inotify` backend. Tested with gcc-7.4/clang-6, ubuntu 18.04 LTS
|
||||||
|
- MacOS: `FSEvents` backend. Tested with MacOS-10.14 clang 10
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
You just have to include the file and use it's functions. It is also compatible with C++ code.
|
||||||
|
Backslashes in Windows paths are also converted to '/' for portability.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define DMON_IMPL
|
||||||
|
#include "dmon.h"
|
||||||
|
|
||||||
|
static void watch_callback(dmon_watch_id watch_id, dmon_action action, const char* rootdir,
|
||||||
|
const char* filepath, const char* oldfilepath, void* user)
|
||||||
|
{
|
||||||
|
// receive change events. type of event is stored in 'action' variable
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
dmon_init();
|
||||||
|
dmon_watch("/path/to/directory", watch_callback, DMON_WATCHFLAGS_RECURSIVE, NULL);
|
||||||
|
// wait ...
|
||||||
|
dmon_deinit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information and how to customize functionality, see [dmon.h](dmon.h)
|
||||||
|
|
||||||
|
To build on linux, link with `pthread`:
|
||||||
|
```gcc test.c -lpthread -o test```
|
||||||
|
|
||||||
|
To build on MacOS, link with `CoreServices` and `CoreFoundation`:
|
||||||
|
```clang test.c -framework CoreFoundation -framework CoreServices -lpthread -o test```
|
||||||
|
|
||||||
|
[License (BSD 2-clause)](https://github.com/septag/dmon/blob/master/LICENSE)
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
<a href="http://opensource.org/licenses/BSD-2-Clause" target="_blank">
|
||||||
|
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
Copyright 2019 Sepehr Taghdisian. All rights reserved.
|
||||||
|
|
||||||
|
https://github.com/septag/dmon
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DMON_IMPL
|
||||||
|
#include "dmon.h"
|
||||||
|
|
||||||
|
static void watch_callback(dmon_watch_id watch_id, dmon_action action, const char* rootdir,
|
||||||
|
const char* filepath, const char* oldfilepath, void* user)
|
||||||
|
{
|
||||||
|
(void)(user);
|
||||||
|
(void)(watch_id);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case DMON_ACTION_CREATE:
|
||||||
|
printf("CREATE: [%s]%s\n", rootdir, filepath);
|
||||||
|
break;
|
||||||
|
case DMON_ACTION_DELETE:
|
||||||
|
printf("DELETE: [%s]%s\n", rootdir, filepath);
|
||||||
|
break;
|
||||||
|
case DMON_ACTION_MODIFY:
|
||||||
|
printf("MODIFY: [%s]%s\n", rootdir, filepath);
|
||||||
|
break;
|
||||||
|
case DMON_ACTION_MOVE:
|
||||||
|
printf("MOVE: [%s]%s -> [%s]%s\n", rootdir, oldfilepath, rootdir, filepath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc > 1) {
|
||||||
|
dmon_init();
|
||||||
|
puts("waiting for changes ..");
|
||||||
|
dmon_watch(argv[1], watch_callback, DMON_WATCHFLAGS_RECURSIVE, NULL);
|
||||||
|
getchar();
|
||||||
|
dmon_deinit();
|
||||||
|
} else {
|
||||||
|
puts("usage: test dirname");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 70a061109d8f9ba36442c27fafc2f6e6c8c7af99
|
||||||
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 84f2045a79a4aa2454801a98e2de0401bd9c8aee
|
||||||
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 7f1f94b66762df19570505219c9031f9a411c649
|
||||||
@ -1,30 +0,0 @@
|
|||||||
# docco output directory
|
|
||||||
#docs/
|
|
||||||
|
|
||||||
# local files for remembering stuff
|
|
||||||
HISTO
|
|
||||||
TODO
|
|
||||||
|
|
||||||
# temporary files
|
|
||||||
.*.swp
|
|
||||||
|
|
||||||
# object files
|
|
||||||
*.o
|
|
||||||
*.obj
|
|
||||||
|
|
||||||
# libraries
|
|
||||||
*.so
|
|
||||||
*.dll
|
|
||||||
*.a
|
|
||||||
*.lib
|
|
||||||
*.exp
|
|
||||||
|
|
||||||
# executables
|
|
||||||
*.exe
|
|
||||||
|
|
||||||
# precompiled Lua bytecode files
|
|
||||||
*.luac
|
|
||||||
|
|
||||||
# LuaRocks packages
|
|
||||||
*.rock
|
|
||||||
|
|
||||||
@ -1,552 +0,0 @@
|
|||||||
# Moon -- A C Binding Toolkit for Lua #
|
|
||||||
|
|
||||||
This library provides new convenience functions for binding C types to
|
|
||||||
Lua as userdata for Lua 5.1, Lua 5.2, and Lua 5.3. It supports objects
|
|
||||||
with different lifetimes, polymorphic type checking, type-safe binding
|
|
||||||
of tagged unions or embedded structs, properties and methods at the
|
|
||||||
same time, and uniform handling of pointers to objects using a simple
|
|
||||||
and small set of API functions.
|
|
||||||
|
|
||||||
|
|
||||||
## Using this Library ##
|
|
||||||
|
|
||||||
This package includes a header file `moon.h` and the corresponding
|
|
||||||
source file `moon.c`. To use this package you need to include the
|
|
||||||
header file wherever you want to call one of the macros/functions
|
|
||||||
defined within. If you just have a single source file where you want
|
|
||||||
to use those functions, you are done: `moon.h` includes `moon.c` and
|
|
||||||
makes every function `static`. If you have multiple source files that
|
|
||||||
need functions/macros from this library, this approach is flawed,
|
|
||||||
because you will end up with multiple versions of the same functions.
|
|
||||||
Instead include the header wherever you need it, but when you compile
|
|
||||||
those source files, define the macro `MOON_PREFIX` to a unique name
|
|
||||||
to use for all functions in the `moon` library. You also have to
|
|
||||||
compile and link `moon.c` using the same define. This approach will
|
|
||||||
change the common `moon_` prefix to your custom prefix behind the
|
|
||||||
scenes to avoid linker errors in case another library also links to
|
|
||||||
`moon.c`.
|
|
||||||
The header file `moon_flag.h` can be included whenever needed, but it
|
|
||||||
depends on the functions defined in `moon.c`. The `moon_dlfix.h`
|
|
||||||
header is completely independent, but relies on some platform specific
|
|
||||||
functions.
|
|
||||||
|
|
||||||
|
|
||||||
## Reference ##
|
|
||||||
|
|
||||||
This section lists all provided macros/functions.
|
|
||||||
|
|
||||||
|
|
||||||
### `moon.h`/`moon.c` ###
|
|
||||||
|
|
||||||
The main part of the moon toolkit.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_EXPORT`, `MOON_IMPORT`, `MOON_LOCAL` ####
|
|
||||||
|
|
||||||
#define MOON_EXPORT
|
|
||||||
#define MOON_IMPORT
|
|
||||||
#define MOON_LOCAL
|
|
||||||
|
|
||||||
Macros for specifying symbol visibility.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_CONCAT` ####
|
|
||||||
|
|
||||||
#define MOON_CONCAT( _a, _b )
|
|
||||||
|
|
||||||
A macro that evaluates both arguments and joins them together. You can
|
|
||||||
use that to build valid C identifiers with custom prefixes or
|
|
||||||
suffixes.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_STRINGIFY` ####
|
|
||||||
|
|
||||||
#define MOON_STRINGIFY( _v )
|
|
||||||
|
|
||||||
A macro that has the same effect as `#_v`, but works outside of a
|
|
||||||
macro substitution.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_object_header` ####
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char flags;
|
|
||||||
unsigned char cleanup_offset;
|
|
||||||
unsigned char vcheck_offset;
|
|
||||||
unsigned char object_offset;
|
|
||||||
} moon_object_header;
|
|
||||||
|
|
||||||
Common data structure shared by all userdata objects created via the
|
|
||||||
moon toolkit. The object may have optional fields following the memory
|
|
||||||
of this header structure, stored at the given offsets. The `flags`
|
|
||||||
field is a bit mask describing the details of the object. A pointer to
|
|
||||||
this header can be obtained by using plain `lua_touserdata` on a moon
|
|
||||||
object.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_object_cast` ####
|
|
||||||
|
|
||||||
typedef void* (*moon_object_cast)( void* );
|
|
||||||
|
|
||||||
Function pointer type for conversion functions used by `moon_defcast`.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_object_destructor` ####
|
|
||||||
|
|
||||||
typedef void (*moon_object_destructor)( void* );
|
|
||||||
|
|
||||||
Function pointer type for cleanup functions of moon objects.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_OBJECT_IS_VALID`, `MOON_OBJECT_IS_POINTER` ####
|
|
||||||
|
|
||||||
#define MOON_OBJECT_IS_VALID 0x01
|
|
||||||
#define MOON_OBJECT_IS_POINTER 0x02
|
|
||||||
|
|
||||||
Values stored in the `flags` field of the `moon_object_header`
|
|
||||||
structure. The only value interesting for users of the library is the
|
|
||||||
`MOON_OBJECT_IS_VALID` flag which is reset automatically by the
|
|
||||||
`moon_killobject` function to signal that the destructor has already
|
|
||||||
run.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_defobject` ####
|
|
||||||
|
|
||||||
/* [ -nup, +0, e ] */
|
|
||||||
void moon_defobject( lua_State* L,
|
|
||||||
char const* metatable_name,
|
|
||||||
size_t userdata_size,
|
|
||||||
luaL_Reg const* methods,
|
|
||||||
int nup );
|
|
||||||
|
|
||||||
This function creates a new metatable and registers the functions in
|
|
||||||
the `luaL_Reg` array (functions starting with double underscores `__`
|
|
||||||
go into the metatable, functions starting with a fullstop `.` are
|
|
||||||
setup as properties, and the rest goes into a table used by the
|
|
||||||
`__index` metafield). Property functions act as `__index` and
|
|
||||||
`__newindex` functions at the same time, i.e. they should return a
|
|
||||||
value when called with two arguments, and assign the third value when
|
|
||||||
called with three. If the `luaL_Reg` array also contains an `__index`
|
|
||||||
and/or `__newindex` function, those functions are called as fallbacks
|
|
||||||
when method/property lookup has failed. In case a metatable with the
|
|
||||||
given name already exists, an error is raised. The `userdata_size` is
|
|
||||||
stored in the metatable for the `moon_newobject` function -- use a
|
|
||||||
size of 0 to prohibit use of `moon_newobject` (e.g. for incomplete
|
|
||||||
types). If `nup` is non-zero, it pops those upvalues from the current
|
|
||||||
Lua stack top and makes them available to all registered functions
|
|
||||||
(metamethods, property functions, *and* methods). A `__gc` metamethod
|
|
||||||
and a default `__tostring` metamethod are provided by `moon_defobject`
|
|
||||||
as well.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_newobject` ####
|
|
||||||
|
|
||||||
/* [ -0, +1, e ] */
|
|
||||||
void* moon_newobject( lua_State* L,
|
|
||||||
char const* metatable_name,
|
|
||||||
moon_object_destructor destructor );
|
|
||||||
|
|
||||||
This function allocates a userdata, sets a metatable, and stores the
|
|
||||||
cleanup function for later use by the `__gc` metamethod or the
|
|
||||||
`moon_killobject` function. It throws an error if the `metatable_name`
|
|
||||||
has not been registered via the `moon_defobject` function. The new
|
|
||||||
userdata object is pushed to the top of the Lua stack, and a pointer
|
|
||||||
to the payload (*not* the `moon_object_header` structure) is returned.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_newpointer` ####
|
|
||||||
|
|
||||||
/* [ -0, +1, e ] */
|
|
||||||
void** moon_newpointer( lua_State* L,
|
|
||||||
char const* metatable_name,
|
|
||||||
moon_object_destructor destructor );
|
|
||||||
|
|
||||||
This function allocates a userdata suitable for storing a pointer,
|
|
||||||
sets a metatable, and stores the cleanup function for later use by the
|
|
||||||
`__gc` metamethod or the `moon_killobject` function. It is equivalent
|
|
||||||
to `moon_newobject` with the difference that the payload is stored as
|
|
||||||
a pointer, not inside the userdata memory. The pointer is initialized
|
|
||||||
to `NULL` when this function returns, and may be set by assigning to
|
|
||||||
the memory location pointed to by the return value.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_newfield` ####
|
|
||||||
|
|
||||||
/* [ -0, +1, e ] */
|
|
||||||
void** moon_newfield( lua_State* L,
|
|
||||||
char const* metatable_name,
|
|
||||||
int idx,
|
|
||||||
int (*isvalid)( void* p ),
|
|
||||||
void* p );
|
|
||||||
|
|
||||||
This function allocates a userdata suitable for storing a pointer, and
|
|
||||||
sets a metatable. It is similar to `moon_newpointer`, but it is
|
|
||||||
intended for exposing a data structure embedded within another
|
|
||||||
userdata (referenced by stack position `idx`). The resulting moon
|
|
||||||
object keeps the parent userdata alive by storing a reference in its
|
|
||||||
uservalue table. If `idx` is `0`, no uservalue table is set. Setting a
|
|
||||||
cleanup function is not possible, because the parent userdata is
|
|
||||||
responsible for cleaning up memory and other resources.
|
|
||||||
If an `isvalid` function pointer is provided, it is called by the
|
|
||||||
`moon_checkobject`/`moon_testobject` functions to check whether the
|
|
||||||
object is still valid. This can be used to make sure that a tagged
|
|
||||||
union used as parent userdata still has the correct type, or that the
|
|
||||||
parent userdata hasn't released any necessary resources prior to
|
|
||||||
garbage collection. If the value referenced by `idx` is a moon object
|
|
||||||
that also has an `isvalid` check registered, all checks are performed
|
|
||||||
in the order from parent object(s) to child object.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_getmethods` ####
|
|
||||||
|
|
||||||
/* [ -0, +(0|1), e ] */
|
|
||||||
int moon_getmethods( lua_State* L,
|
|
||||||
char const* tname );
|
|
||||||
|
|
||||||
If the metatable identified by `tname` has methods registered, pushes
|
|
||||||
the methods table and returns `LUA_TTABLE`. Otherwise nothing is
|
|
||||||
pushed and `LUA_TNIL` is returned. This function only works for moon
|
|
||||||
objects and raises an error if the metatable `tname` wasn't registered
|
|
||||||
via `moon_defobject`.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_killobject` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, e ] */
|
|
||||||
void moon_killobject( lua_State* L,
|
|
||||||
int idx );
|
|
||||||
|
|
||||||
If the moon object at the given stack index is valid, its cleanup
|
|
||||||
function is run, and the object is marked as invalid (to prevent the
|
|
||||||
cleanup function from running again). This function can be used to
|
|
||||||
reclaim resources before the object becomes unreachable.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_defcast` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, e ] */
|
|
||||||
void moon_defcast( lua_State* L,
|
|
||||||
char const* tname1,
|
|
||||||
char const* tname2,
|
|
||||||
moon_object_cast cast );
|
|
||||||
|
|
||||||
Registers the conversion function `cast` for converting userdata
|
|
||||||
objects of type `tname1` to type `tname2`. The `cast` function is
|
|
||||||
called automatically by `moon_checkobject( L, idx, tname2 )` when
|
|
||||||
applied to an object of type `tname1`, so function implementations can
|
|
||||||
be reused without extra work. The metatable `tname1` must already
|
|
||||||
exist and belong to a moon object type (created via `moon_defobject`).
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_checkobject` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, v ] */
|
|
||||||
void* moon_checkobject( lua_State* L,
|
|
||||||
int idx,
|
|
||||||
char const* metatable_name );
|
|
||||||
|
|
||||||
This function ensures that the value stored at stack index `idx`
|
|
||||||
|
|
||||||
1. is a full userdata
|
|
||||||
2. is a moon object
|
|
||||||
3. has the metatable identified by `metatable_name` or has a
|
|
||||||
cast function to `metatable_name` registered
|
|
||||||
4. has the `MOON_OBJECT_IS_VALID` flag set
|
|
||||||
5. all `isvalid` functions return a non-zero value (for objects
|
|
||||||
created via `moon_newfield`)
|
|
||||||
6. contains a non-`NULL` pointer value (for objects created via
|
|
||||||
`moon_newpointer` or `moon_newfield`).
|
|
||||||
|
|
||||||
If any of those conditions are false, an error is raised. Otherwise
|
|
||||||
this function returns a pointer to the object's memory (meaning the
|
|
||||||
objects created via `moon_newpointer` and `moon_newfield` are
|
|
||||||
dereferenced once, and if necessary the registered cast function is
|
|
||||||
called).
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_testobject` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, e ] */
|
|
||||||
void* moon_testobject( lua_State* L,
|
|
||||||
int idx,
|
|
||||||
char const* metatable_name );
|
|
||||||
|
|
||||||
Performs the same checks as `moon_checkobject`, but returns `NULL` if
|
|
||||||
any of those conditions are false instead of raising an error.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_checkint` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, v ] */
|
|
||||||
lua_Integer moon_checkint( lua_State* L,
|
|
||||||
int idx,
|
|
||||||
lua_Integer min,
|
|
||||||
lua_Integer max );
|
|
||||||
|
|
||||||
This function works like `luaL_checkinteger` but additionally ensures
|
|
||||||
that the given value is in the range [`min`, `max`], or else an error
|
|
||||||
is thrown.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_optint` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, v ] */
|
|
||||||
lua_Integer moon_optint( lua_State* L,
|
|
||||||
int idx,
|
|
||||||
lua_Integer min,
|
|
||||||
lua_Integer max,
|
|
||||||
lua_Integer def );
|
|
||||||
|
|
||||||
Similar to `moon_checkint` but uses the default value `def` if the
|
|
||||||
value at the given stack position is `nil` or `none`.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_atexit` ####
|
|
||||||
|
|
||||||
/* [ -0, +1, e ] */
|
|
||||||
int* moon_atexit( lua_State* L,
|
|
||||||
lua_CFunction cleanup );
|
|
||||||
|
|
||||||
This function puts an integer-sized userdata (initialized to 0) in the
|
|
||||||
registry and sets the given `cleanup` function as `__gc` metamethod.
|
|
||||||
The userdata is also pushed to the top of the Lua stack, and returned
|
|
||||||
as an `int` pointer.
|
|
||||||
Use this function if you want to call a cleanup function when the Lua
|
|
||||||
state is closed, but only if some initialization succeeded. The usual
|
|
||||||
approach is as follows:
|
|
||||||
|
|
||||||
1. Call `moon_atexit` registering your cleanup function.
|
|
||||||
2. Do your initialization.
|
|
||||||
3. If successful, you set the `int` pointer to non-zero, which is
|
|
||||||
almost atomic and can't fail, and pop the userdata.
|
|
||||||
4. When the cleanup function is called, check for a non-zero value
|
|
||||||
before actually cleaning up.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_setuvfield` ####
|
|
||||||
|
|
||||||
/* [ -1, +0, e ] */
|
|
||||||
void moon_setuvfield( lua_State* L,
|
|
||||||
int idx,
|
|
||||||
char const* key );
|
|
||||||
|
|
||||||
This function pops the value at the top of the stack and stores it
|
|
||||||
under `key` in the environment/uservalue table of the object at stack
|
|
||||||
position `idx`.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_getuvfield` ####
|
|
||||||
|
|
||||||
/* [ -0, +(0|1), e ] */
|
|
||||||
int moon_getuvfield( lua_State* L,
|
|
||||||
int idx,
|
|
||||||
char const* key );
|
|
||||||
|
|
||||||
This function works similar to `luaL_getmetafield`, but it looks for
|
|
||||||
`key` in the environment/uservalue table of the object at index `idx`,
|
|
||||||
and pushes the corresponding value to the top of the stack. If there
|
|
||||||
is no uservalue table or no such field, nothing is pushed and
|
|
||||||
`LUA_TNIL` is returned. Otherwise, the return value is the type of the
|
|
||||||
pushed value.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_getcache` ####
|
|
||||||
|
|
||||||
/* [ -0, +1, e ] */
|
|
||||||
void moon_getcache( lua_State* L,
|
|
||||||
int idx );
|
|
||||||
|
|
||||||
This function looks up and pushes a weak-valued table under a private
|
|
||||||
key in the table given by index `idx` (often `LUA_REGISTRYINDEX`). If
|
|
||||||
the weak-valued table doesn't exist yet, it is created automatically.
|
|
||||||
This function is useful to map lightuserdata to full userdata, but it
|
|
||||||
can also be used to cache full userdata for enum values (using
|
|
||||||
separate caches per enum type), etc.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_stack_assert` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, v ] */
|
|
||||||
void moon_stack_assert( lua_State* L,
|
|
||||||
... );
|
|
||||||
|
|
||||||
This "function" is implemented as a macro that evaluates to `void` if
|
|
||||||
`NDEBUG` is defined. If it is not, it tries to match the type
|
|
||||||
specifications (strings) given as arguments to the values at the top
|
|
||||||
of the Lua stack. Every mismatch is reported on `stderr`, and finally
|
|
||||||
the whole Lua stack is dumped to `stderr` using the `moon_stack`
|
|
||||||
function below, and an error is raised. Currently the following type
|
|
||||||
specifications are supported:
|
|
||||||
|
|
||||||
* `"n"`: nil
|
|
||||||
* `"b"`: boolean
|
|
||||||
* `"l"`: lightuserdata
|
|
||||||
* `"i"`: integer (equivalent to `"d"` before Lua 5.3)
|
|
||||||
* `"d"`: number (think `double`)
|
|
||||||
* `"s"`: string
|
|
||||||
* `"t"`: table
|
|
||||||
* `"f"`: function
|
|
||||||
* `"u"`: userdata
|
|
||||||
* `"c"`: coroutine
|
|
||||||
* `"a"`: any (non-nil) value
|
|
||||||
|
|
||||||
You can combine the single letter options to express alternatives, so
|
|
||||||
e.g. `"tf"` means: table or function.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_stack` ####
|
|
||||||
|
|
||||||
/* [ -0, +0, - ] */
|
|
||||||
void moon_stack( lua_State* L );
|
|
||||||
|
|
||||||
This "function" is also implemented as a macro that evaluates to
|
|
||||||
`void` in case `NDEBUG` is defined. Otherwise it prints the current
|
|
||||||
contents of the Lua stack in human-readable format to `stderr`.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_absindex` ####
|
|
||||||
|
|
||||||
Compatiblity macro for `lua_absindex`, but also available on Lua 5.1
|
|
||||||
as a function.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_derive` ####
|
|
||||||
|
|
||||||
int moon_derive( lua_State* L );
|
|
||||||
|
|
||||||
A `lua_CFunction` that may be registered as part of your module and
|
|
||||||
allows Lua code to subclass a moon object. When called it expects two
|
|
||||||
strings as arguments: a new (non-existing) type name and an old
|
|
||||||
(existing) type name of a moon object type. It sets up the new type
|
|
||||||
name as an alias to the old type but with a different methods table.
|
|
||||||
The new methods table (initially a copy of the methods of the old
|
|
||||||
type) is returned.
|
|
||||||
|
|
||||||
|
|
||||||
#### `moon_downcast` ####
|
|
||||||
|
|
||||||
int moon_downcast( lua_State* L );
|
|
||||||
|
|
||||||
A `lua_CFunction` that may be registered as part of your module and
|
|
||||||
allows Lua code to change the type of a moon object to a type created
|
|
||||||
via `moon_derive`. It is typically used in constructors of derived
|
|
||||||
types, and expects a moon object and the new type name as arguments.
|
|
||||||
If successful, the object (with its metatable replaced) is returned.
|
|
||||||
|
|
||||||
|
|
||||||
### `moon_flag.h` ###
|
|
||||||
|
|
||||||
`moon_flag.h` is a macro file, that can be included multiple times and
|
|
||||||
each time defines a new userdata type as a type-safe representation of
|
|
||||||
a given enum/flag type in Lua. The resulting userdata values support
|
|
||||||
`+` (bitwise or, in Lua 5.3 also `|`), `-` (create a new value with
|
|
||||||
certain bits cleared), and calling (test if all bits are set). For Lua
|
|
||||||
5.3 also bitwise "and" and bitwise "not" are defined.
|
|
||||||
Parameters are passed as macros before including the macro file. Any
|
|
||||||
arguments and all internal macros are `#undef`ed before leaving the
|
|
||||||
macro file. The following parameters are recognized:
|
|
||||||
|
|
||||||
* `MOON_FLAG_NAME` (required): A metatable name used for defining a
|
|
||||||
userdata type.
|
|
||||||
* `MOON_FLAG_TYPE` (required): The underlying enum/flag type that is
|
|
||||||
handled by the custom userdata.
|
|
||||||
* `MOON_FLAG_SUFFIX` (required): All defined functions have this
|
|
||||||
suffix (and the `moon_flag_` prefix) to make them unique.
|
|
||||||
* `MOON_FLAG_NOBITOPS` (optional): If this macro is defined, no
|
|
||||||
metamethods for bitwise operations are created. This includes
|
|
||||||
`__add`, `__sub`, and `__call` metamethods. If you do this, you
|
|
||||||
should think about using strings and `luaL_checkoption` instead of
|
|
||||||
userdata for representing your flags in Lua.
|
|
||||||
* `MOON_FLAG_NORELOPS` (optional): If this macro is defined, the
|
|
||||||
`__eq` metamethod is not created.
|
|
||||||
* `MOON_FLAG_USECACHE` (optional): The constructor function for this
|
|
||||||
flag looks in a local cache before creating a new full userdata,
|
|
||||||
and returns the cached value if possible. This way each enum/flag
|
|
||||||
value has at most one userdata associated with it.
|
|
||||||
* `MOON_FLAG_EQMETHOD( _a, _b )` (optional): If you need a custom
|
|
||||||
comparison operation instead of the usual `==`, define this macro.
|
|
||||||
|
|
||||||
The following (static) functions will be defined, unless they are
|
|
||||||
disabled via one of the parameter macros above:
|
|
||||||
|
|
||||||
/* [ -0, +0, e ] */
|
|
||||||
void moon_flag_def_SUFFIX( lua_State* L );
|
|
||||||
/* [ -0, +1, e ] */
|
|
||||||
void moon_flag_new_SUFFIX( lua_State* L, TYPE value );
|
|
||||||
/* [ -0, +0, v ] */
|
|
||||||
TYPE moon_flag_get_SUFFIX( lua_State* L, int idx );
|
|
||||||
|
|
||||||
int moon_flag_add_SUFFIX( lua_State* L );
|
|
||||||
int moon_flag_sub_SUFFIX( lua_State* L );
|
|
||||||
int moon_flag_call_SUFFIX( lua_State* L );
|
|
||||||
int moon_flag_and_SUFFIX( lua_State* L ); /* Lua 5.3+ */
|
|
||||||
int moon_flag_not_SUFFIX( lua_State* L ); /* Lua 5.3+ */
|
|
||||||
int moon_flag_eq_SUFFIX( lua_State* L );
|
|
||||||
|
|
||||||
The last six are metamethods and not supposed to be called from C.
|
|
||||||
`moon_flag_def_SUFFIX` defines the new type, creates the metatable and
|
|
||||||
registers all metamethods. `moon_flag_new_SUFFIX` pushes a userdata
|
|
||||||
representing the given value to the top of the Lua stack, while
|
|
||||||
`moon_flag_get_SUFFIX` returns the corresponding enum value from a
|
|
||||||
userdata on the Lua stack (or raises an error).
|
|
||||||
|
|
||||||
|
|
||||||
### `moon_dlfix.h` ###
|
|
||||||
|
|
||||||
On Linux and BSDs (and possibly other Unix machines) binary extension
|
|
||||||
modules aren't linked to the Lua library directly, but instead expect
|
|
||||||
the main executable to reexport the Lua API. If you don't have control
|
|
||||||
over the main executable (e.g. you are writing a plugin for a 3rd
|
|
||||||
party program), you are out of luck. This header file tries to
|
|
||||||
reexport the Lua API from the shared library linked to your plugin to
|
|
||||||
make it available for extension modules. It relies on some platform
|
|
||||||
specific tricks, so it probably won't work everywhere.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_DLFIX` ####
|
|
||||||
|
|
||||||
#define MOON_DLFIX()
|
|
||||||
|
|
||||||
This macro uses the dynamic linker to search for the Lua API in an
|
|
||||||
already loaded shared library and reexport it for extension modules.
|
|
||||||
If the necessary linker tricks don't work on the given platform, this
|
|
||||||
macro evaluates to a `void` expression, and you will continue to get
|
|
||||||
the usual unresolved symbol errors when loading a binary extension
|
|
||||||
module.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_DLFIX_LIBNAME` ####
|
|
||||||
|
|
||||||
If the builtin heuristics fail to find the shared Lua library you can
|
|
||||||
specify the library name/path by defining this macro.
|
|
||||||
|
|
||||||
|
|
||||||
#### `MOON_DLFIX_LIBPREFIX` ####
|
|
||||||
|
|
||||||
For some OSes *all* loaded shared libraries is searched for an ELF
|
|
||||||
object that contains the Lua symbols. Since this procedure also finds
|
|
||||||
shared objects that have the Lua library as a dependency, the library
|
|
||||||
name is checked for a known prefix to make sure that only the actual
|
|
||||||
Lua library is exported. The default is `"liblua"`, but you can change
|
|
||||||
it by defining this macro.
|
|
||||||
|
|
||||||
|
|
||||||
## Contact ##
|
|
||||||
|
|
||||||
Philipp Janda, siffiejoe(a)gmx.net
|
|
||||||
|
|
||||||
Comments and feedback are always welcome.
|
|
||||||
|
|
||||||
|
|
||||||
## License ##
|
|
||||||
|
|
||||||
`moon` is *copyrighted free software* distributed under the Tiny
|
|
||||||
license. The full license text follows:
|
|
||||||
|
|
||||||
moon (c) 2013-2016 Philipp Janda
|
|
||||||
|
|
||||||
You may do anything with this work that copyright law would normally
|
|
||||||
restrict, so long as you retain the above notice(s) and this license
|
|
||||||
in all redistributed copies and derived works. There is no warranty.
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include "plugin.h"
|
|
||||||
|
|
||||||
int main( void ) {
|
|
||||||
int ret = EXIT_FAILURE;
|
|
||||||
void* lib = dlopen( "./plugin.so", RTLD_LAZY|RTLD_LOCAL );
|
|
||||||
void* sym = NULL;
|
|
||||||
plugin f;
|
|
||||||
if( !lib || !(sym = dlsym( lib, PLUGIN )) ) {
|
|
||||||
fprintf( stderr, "ERROR: %s\n", dlerror() );
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
f = (plugin)sym;
|
|
||||||
ret = f();
|
|
||||||
error:
|
|
||||||
if( lib )
|
|
||||||
dlclose( lib );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
#include <lua.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
#include "moon.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MOON_FLAG_NAME "X"
|
|
||||||
#define MOON_FLAG_TYPE unsigned
|
|
||||||
#define MOON_FLAG_SUFFIX X
|
|
||||||
#define MOON_FLAG_USECACHE
|
|
||||||
#include "moon_flag.h"
|
|
||||||
|
|
||||||
#define MOON_FLAG_NAME "Y"
|
|
||||||
#define MOON_FLAG_TYPE unsigned
|
|
||||||
#define MOON_FLAG_SUFFIX Y
|
|
||||||
#include "moon_flag.h"
|
|
||||||
|
|
||||||
|
|
||||||
static int flgex_getXmethods( lua_State* L ) {
|
|
||||||
if( moon_getmethods( L, "X" ) == LUA_TNIL )
|
|
||||||
lua_pushnil( L );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaopen_flgex( lua_State* L ) {
|
|
||||||
luaL_Reg const flgex_funcs[] = {
|
|
||||||
{ "getXmethods", flgex_getXmethods },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
/* define the flags and create their metatables */
|
|
||||||
moon_flag_def_X( L );
|
|
||||||
moon_flag_def_Y( L );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
luaL_register( L, "flgex", flgex_funcs );
|
|
||||||
#else
|
|
||||||
luaL_newlib( L, flgex_funcs );
|
|
||||||
#endif
|
|
||||||
/* create some predefined flags */
|
|
||||||
moon_flag_new_X( L, 0 );
|
|
||||||
lua_setfield( L, -2, "NULL" );
|
|
||||||
moon_flag_new_X( L, 1 );
|
|
||||||
lua_setfield( L, -2, "ONE" );
|
|
||||||
moon_flag_new_X( L, 2 );
|
|
||||||
lua_setfield( L, -2, "TWO" );
|
|
||||||
moon_flag_new_Y( L, 4 );
|
|
||||||
lua_setfield( L, -2, "THREE" );
|
|
||||||
moon_flag_new_Y( L, 8 );
|
|
||||||
lua_setfield( L, -2, "FOUR" );
|
|
||||||
/* we don't use those functions in this example: */
|
|
||||||
(void)moon_flag_get_X;
|
|
||||||
(void)moon_flag_get_Y;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,528 +0,0 @@
|
|||||||
/*
|
|
||||||
* Example code for userdata handling in the moon toolkit.
|
|
||||||
*
|
|
||||||
* The moon toolkits provides the following functions for handling
|
|
||||||
* userdata in an easy and safe way:
|
|
||||||
* - moon_defobject
|
|
||||||
* - moon_newobject
|
|
||||||
* - moon_newpointer
|
|
||||||
* - moon_newfield
|
|
||||||
* - moon_killobject
|
|
||||||
* - moon_checkobject
|
|
||||||
* - moon_testobject
|
|
||||||
* - moon_defcast
|
|
||||||
*
|
|
||||||
* Using those functions enables you to
|
|
||||||
* - Create and register a new metatable for a C type in a single
|
|
||||||
* function call, including methods and metamethods with upvalues.
|
|
||||||
* - Have properties and methods for an object at the same time.
|
|
||||||
* - Use C values and pointers to those values in a uniform way.
|
|
||||||
* - Support multiple different ways to create/destroy a C type.
|
|
||||||
* - Expose fields embedded in another object in a type-safe way.
|
|
||||||
* - Bind tagged unions in a type-safe way.
|
|
||||||
* - Define functions that release resources in a safe way before
|
|
||||||
* the object becomes unreachable.
|
|
||||||
* - Use userdata polymorphically (use one method implementation for
|
|
||||||
* multiple similar types).
|
|
||||||
*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <lua.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
#include "moon.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Types to be exposed to Lua: */
|
|
||||||
typedef struct {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
} D;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
D d;
|
|
||||||
} C;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
double f;
|
|
||||||
} B;
|
|
||||||
|
|
||||||
#define TYPE_B 1
|
|
||||||
#define TYPE_C 2
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int tag;
|
|
||||||
union {
|
|
||||||
B b;
|
|
||||||
C c;
|
|
||||||
} u;
|
|
||||||
} A;
|
|
||||||
|
|
||||||
|
|
||||||
/* Check functions to make sure that embedded userdata are still
|
|
||||||
* valid. A change in the tagged union (A_switch) or running a cleanup
|
|
||||||
* function (C_close) can make embedded userdata invalid. */
|
|
||||||
static int type_b_check( void* p ) {
|
|
||||||
int* tagp = p;
|
|
||||||
int res = *tagp == TYPE_B;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int type_c_check( void* p ) {
|
|
||||||
int* tagp = p;
|
|
||||||
int res = *tagp == TYPE_C;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int object_valid_check( void* p ) {
|
|
||||||
unsigned char* flagp = p;
|
|
||||||
int res = *flagp & MOON_OBJECT_IS_VALID;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Types that are similar can share one method implementation, but a
|
|
||||||
* pointer to one type has to be transformed to a pointer to the other
|
|
||||||
* type. This is probably much more useful when binding C++ libraries
|
|
||||||
* with proper type hierarchies! */
|
|
||||||
static void* C_to_D( void* p ) {
|
|
||||||
C* c = p;
|
|
||||||
printf( "casting C to D\n" );
|
|
||||||
return &(c->d);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* The (meta-)methods are pretty straightforward. Just use
|
|
||||||
* `moon_checkobject` instead of `luaL_checkudata`. */
|
|
||||||
static int A_index( lua_State* L ) {
|
|
||||||
A* a = moon_checkobject( L, 1, "A" );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
if( 0 == strcmp( key, "tag" ) ) {
|
|
||||||
lua_pushstring( L, a->tag == TYPE_B ? "b" : "c" );
|
|
||||||
} else if( 0 == strcmp( key, "b" ) && a->tag == TYPE_B ) {
|
|
||||||
/* To avoid creating the sub-userdata on every __index access, the
|
|
||||||
* userdata values are cached in the uservalue field of the parent
|
|
||||||
* using the same field name as in the struct. */
|
|
||||||
if( moon_getuvfield( L, 1, "b" ) == LUA_TNIL ) {
|
|
||||||
/* Create a new userdata that represents a field in another
|
|
||||||
* object already exposed to Lua. A gc function is unnecessary
|
|
||||||
* since the parent userdata already takes care of that.
|
|
||||||
* However, the parent userdata must be kept alive long enough
|
|
||||||
* (by putting the value at index 1 into the uservalue table of
|
|
||||||
* the new userdata), and the new userdata may only be used as
|
|
||||||
* long as the `a->tag` field satisfies the `type_b_check`
|
|
||||||
* function! */
|
|
||||||
void** p = moon_newfield( L, "B", 1, type_b_check, &(a->tag) );
|
|
||||||
/* The userdata stores a pointer to the `a->b` field. */
|
|
||||||
*p = &(a->u.b);
|
|
||||||
lua_pushvalue( L, -1 );
|
|
||||||
moon_setuvfield( L, 1, "b" );
|
|
||||||
}
|
|
||||||
} else if( 0 == strcmp( key, "c" ) && a->tag == TYPE_C ) {
|
|
||||||
if( moon_getuvfield( L, 1, "c" ) == LUA_TNIL ) {
|
|
||||||
void** p = moon_newfield( L, "C", 1, type_c_check, &(a->tag) );
|
|
||||||
*p = &(a->u.c);
|
|
||||||
lua_pushvalue( L, -1 );
|
|
||||||
moon_setuvfield( L, 1, "c" );
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
lua_pushnil( L );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int A_switch( lua_State* L ) {
|
|
||||||
A* a = moon_checkobject( L, 1, "A" );
|
|
||||||
lua_settop( L, 1 );
|
|
||||||
if( a->tag == TYPE_B ) {
|
|
||||||
a->tag = TYPE_C;
|
|
||||||
a->u.c.d.x = 0;
|
|
||||||
a->u.c.d.y = 0;
|
|
||||||
} else {
|
|
||||||
a->tag = TYPE_B;
|
|
||||||
a->u.b.f = 0.0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int A_printme( lua_State* L ) {
|
|
||||||
A* a = moon_checkobject( L, 1, "A" );
|
|
||||||
if( a->tag == TYPE_B )
|
|
||||||
printf( "A { u.b.f = %g }\n", a->u.b.f );
|
|
||||||
else
|
|
||||||
printf( "A { u.c.d = { x = %d, y = %d } }\n",
|
|
||||||
a->u.c.d.x, a->u.c.d.y );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int B_property_f( lua_State* L ) {
|
|
||||||
B* b = moon_checkobject( L, 1, "B" );
|
|
||||||
printf( "property{f} B (uv1: %d, uv2: %d)\n",
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
|
|
||||||
if( lua_gettop( L ) < 3 ) { /* __index */
|
|
||||||
lua_pushnumber( L, b->f );
|
|
||||||
return 1;
|
|
||||||
} else { /* __newindex */
|
|
||||||
b->f = luaL_checknumber( L, 3 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int B_index( lua_State* L ) {
|
|
||||||
B* b = moon_checkobject( L, 1, "B" );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
printf( "__index B (uv1: %d, uv2: %d)\n",
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
|
|
||||||
if( 0 == strcmp( key, "f" ) ) {
|
|
||||||
lua_pushnumber( L, b->f );
|
|
||||||
} else
|
|
||||||
lua_pushnil( L );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int B_newindex( lua_State* L ) {
|
|
||||||
B* b = moon_checkobject( L, 1, "B" );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
printf( "__newindex B (uv1: %d, uv2: %d)\n",
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
|
|
||||||
if( 0 == strcmp( key, "f" ) )
|
|
||||||
b->f = luaL_checknumber( L, 3 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static int B_printme( lua_State* L ) {
|
|
||||||
B* b = moon_checkobject( L, 1, "B" );
|
|
||||||
printf( "B { f = %g }\n", b->f );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int C_index( lua_State* L ) {
|
|
||||||
C* c = moon_checkobject( L, 1, "C" );
|
|
||||||
/* You can get a pointer to the `moon_object_header` structure
|
|
||||||
* common to all objects created via the moon toolkit by using the
|
|
||||||
* normal `lua_touserdata` function: */
|
|
||||||
moon_object_header* h = lua_touserdata( L, 1 );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
printf( "__index C (uv1: %d, uv2: %d)\n",
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
|
|
||||||
if( 0 == strcmp( key, "d" ) ) {
|
|
||||||
if( moon_getuvfield( L, 1, "d" ) == LUA_TNIL ) {
|
|
||||||
/* The `object_valid_check` makes sure that the parent object
|
|
||||||
* has the `MOON_OBJECT_IS_VALID` flag set. This flag is reset
|
|
||||||
* by the `moon_killobject` function. */
|
|
||||||
void** p = moon_newfield( L, "D", 1, object_valid_check, &h->flags );
|
|
||||||
*p = &(c->d);
|
|
||||||
lua_pushvalue( L, -1 );
|
|
||||||
moon_setuvfield( L, 1, "d" );
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
lua_pushnil( L );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int C_newindex( lua_State* L ) {
|
|
||||||
C* c = moon_checkobject( L, 1, "C" );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
printf( "__newindex C (uv1: %d, uv2: %d)\n",
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
|
|
||||||
if( 0 == strcmp( key, "d" ) ) {
|
|
||||||
D* d = moon_checkobject( L, 3, "D" );
|
|
||||||
c->d = *d;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int C_close( lua_State* L ) {
|
|
||||||
/* Use `moon_testobject` here to test it. `moon_checkobject` would
|
|
||||||
* make more sense in practice! */
|
|
||||||
if( !moon_testobject( L, 1, "C" ) )
|
|
||||||
luaL_error( L, "need a 'C' object" );
|
|
||||||
/* Run cleanup function (if any) to release resources and mark the
|
|
||||||
* C object as invalid. `moon_checkobject` will raise an error for
|
|
||||||
* invalid objects. */
|
|
||||||
moon_killobject( L, 1 );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int C_printme( lua_State* L ) {
|
|
||||||
C* c = moon_checkobject( L, 1, "C" );
|
|
||||||
printf( "C { d = { x = %d, y = %d } } (uv1: %d, uv2: %d)\n",
|
|
||||||
c->d.x, c->d.y,
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 1 ) ),
|
|
||||||
(int)lua_tointeger( L, lua_upvalueindex( 2 ) ) );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int D_index( lua_State* L ) {
|
|
||||||
D* d = moon_checkobject( L, 1, "D" );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
if( 0 == strcmp( key, "x" ) )
|
|
||||||
lua_pushinteger( L, d->x );
|
|
||||||
else if( 0 == strcmp( key, "y" ) )
|
|
||||||
lua_pushinteger( L, d->y );
|
|
||||||
else {
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_getfenv( L, 1 );
|
|
||||||
#else
|
|
||||||
lua_getuservalue( L, 1 );
|
|
||||||
#endif
|
|
||||||
lua_pushvalue( L, 2 );
|
|
||||||
lua_rawget( L, -2 );
|
|
||||||
lua_replace( L, -2 );
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int D_newindex( lua_State* L ) {
|
|
||||||
D* d = moon_checkobject( L, 1, "D" );
|
|
||||||
char const* key = luaL_checkstring( L, 2 );
|
|
||||||
if( 0 == strcmp( key, "x" ) )
|
|
||||||
d->x = (int)moon_checkint( L, 3, INT_MIN, INT_MAX );
|
|
||||||
else if( 0 == strcmp( key, "y" ) )
|
|
||||||
d->y = (int)moon_checkint( L, 3, INT_MIN, INT_MAX );
|
|
||||||
else {
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_getfenv( L, 1 );
|
|
||||||
#else
|
|
||||||
lua_getuservalue( L, 1 );
|
|
||||||
#endif
|
|
||||||
lua_pushvalue( L, 2 );
|
|
||||||
lua_pushvalue( L, 3 );
|
|
||||||
lua_rawset( L, -3 );
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int D_printme( lua_State* L ) {
|
|
||||||
D* d = moon_checkobject( L, 1, "D" );
|
|
||||||
printf( "D { x = %d, y = %d }\n", d->x, d->y );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int D_vcall( lua_State* L ) {
|
|
||||||
moon_checkobject( L, 1, "D" );
|
|
||||||
lua_getfield( L, 1, "func" );
|
|
||||||
if( lua_isfunction( L, -1 ) ) {
|
|
||||||
lua_insert( L, 1 );
|
|
||||||
lua_call( L, lua_gettop( L )-1, LUA_MULTRET );
|
|
||||||
return lua_gettop( L );
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int objex_getAmethods( lua_State* L ) {
|
|
||||||
if( moon_getmethods( L, "A" ) == LUA_TNIL )
|
|
||||||
lua_pushnil( L );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int objex_newA( lua_State* L ) {
|
|
||||||
/* Create a new A object. The memory is allocated inside the
|
|
||||||
* userdata when using `moon_newobject`. Here no cleanup function
|
|
||||||
* is used (0 pointer). */
|
|
||||||
A* ud = moon_newobject( L, "A", 0 );
|
|
||||||
ud->tag = TYPE_B;
|
|
||||||
ud->u.b.f = 0.0;
|
|
||||||
/* `moon_newobject`, and `moon_newpointer` don't allocate a
|
|
||||||
* uservalue table by default. `moon_newfield` only does if the
|
|
||||||
* given index is non-zero. If you need a uservalue table (e.g. to
|
|
||||||
* cache embedded userdatas), you have to add one yourself: */
|
|
||||||
lua_newtable( L );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_setfenv( L, -2 );
|
|
||||||
#else
|
|
||||||
lua_setuservalue( L, -2 );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int objex_newB( lua_State* L ) {
|
|
||||||
B* b = moon_newobject( L, "B", 0 );
|
|
||||||
b->f = 0.0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void C_destructor( void* p ) {
|
|
||||||
printf( "destroying C: %p\n", p );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int objex_newC( lua_State* L ) {
|
|
||||||
/* Create a C object and register a dummy cleanup function (just
|
|
||||||
* for tests): */
|
|
||||||
C* c = moon_newobject( L, "C", C_destructor );
|
|
||||||
c->d.x = 0;
|
|
||||||
c->d.y = 0;
|
|
||||||
printf( "creating C: %p\n", (void*)c );
|
|
||||||
lua_newtable( L );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_setfenv( L, -2 );
|
|
||||||
#else
|
|
||||||
lua_setuservalue( L, -2 );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int objex_newD( lua_State* L ) {
|
|
||||||
D* d = moon_newobject( L, "D", 0 );
|
|
||||||
d->x = 0;
|
|
||||||
d->y = 0;
|
|
||||||
lua_newtable( L );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_setfenv( L, -2 );
|
|
||||||
#else
|
|
||||||
lua_setuservalue( L, -2 );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int objex_getD( lua_State* L ) {
|
|
||||||
static D d = { 1, 2 };
|
|
||||||
/* `moon_newpointer` without a cleanup function can be used to
|
|
||||||
* expose a global variable to Lua: */
|
|
||||||
void** ud = moon_newpointer( L, "D", 0 );
|
|
||||||
*ud = &d;
|
|
||||||
lua_newtable( L );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_setfenv( L, -2 );
|
|
||||||
#else
|
|
||||||
lua_setuservalue( L, -2 );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static D* newD( int x, int y ) {
|
|
||||||
D* d = malloc( sizeof( *d ) );
|
|
||||||
if( d ) {
|
|
||||||
printf( "allocating D: %p\n", (void*)d );
|
|
||||||
d->x = x;
|
|
||||||
d->y = y;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freeD( void* d ) {
|
|
||||||
printf( "deallocating D: %p\n", d );
|
|
||||||
free( d );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int objex_makeD( lua_State* L ) {
|
|
||||||
int x = (int)moon_checkint( L, 1, INT_MIN, INT_MAX );
|
|
||||||
int y = (int)moon_checkint( L, 2, INT_MIN, INT_MAX );
|
|
||||||
/* Usually, `moon_newpointer` is used when your API handles memory
|
|
||||||
* allocation and deallocation for its types: */
|
|
||||||
void** p = moon_newpointer( L, "D", freeD );
|
|
||||||
/* The cleanup function will only run if the pointer is set to a
|
|
||||||
* non-NULL value. `moon_checkobject` also will raise an error when
|
|
||||||
* passed a NULL object! */
|
|
||||||
*p = newD( x, y );
|
|
||||||
if( !*p )
|
|
||||||
luaL_error( L, "memory allocation error" );
|
|
||||||
lua_newtable( L );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
lua_setfenv( L, -2 );
|
|
||||||
#else
|
|
||||||
lua_setuservalue( L, -2 );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaopen_objex( lua_State* L ) {
|
|
||||||
luaL_Reg const objex_funcs[] = {
|
|
||||||
{ "getAmethods", objex_getAmethods },
|
|
||||||
{ "newA", objex_newA },
|
|
||||||
{ "newB", objex_newB },
|
|
||||||
{ "newC", objex_newC },
|
|
||||||
{ "newD", objex_newD },
|
|
||||||
{ "getD", objex_getD },
|
|
||||||
{ "makeD", objex_makeD },
|
|
||||||
{ "derive", moon_derive },
|
|
||||||
{ "downcast", moon_downcast },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
/* You put metamethods and normal methods in the same luaL_Reg
|
|
||||||
* array. `moon_defobject` puts the functions in the right place
|
|
||||||
* automatically. */
|
|
||||||
luaL_Reg const A_methods[] = {
|
|
||||||
{ "__index", A_index },
|
|
||||||
{ "switch", A_switch },
|
|
||||||
{ "printme", A_printme },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
luaL_Reg const B_methods[] = {
|
|
||||||
{ ".f", B_property_f },
|
|
||||||
#if 0
|
|
||||||
{ "__index", B_index },
|
|
||||||
{ "__newindex", B_newindex },
|
|
||||||
{ "printme", B_printme },
|
|
||||||
#endif
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
luaL_Reg const C_methods[] = {
|
|
||||||
{ "__index", C_index },
|
|
||||||
{ "__newindex", C_newindex },
|
|
||||||
{ "printme", C_printme },
|
|
||||||
/* A C object can be cast to a D object (see below), so C objects
|
|
||||||
* can use the methods of the D type! */
|
|
||||||
{ "printmeD", D_printme },
|
|
||||||
{ "close", C_close },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
luaL_Reg const D_methods[] = {
|
|
||||||
{ "__index", D_index },
|
|
||||||
{ "__newindex", D_newindex },
|
|
||||||
{ "printme", D_printme },
|
|
||||||
{ "vcall", D_vcall },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
/* All object types must be defined once (this creates the
|
|
||||||
* metatables): */
|
|
||||||
moon_defobject( L, "A", sizeof( A ), A_methods, 0 );
|
|
||||||
(void)B_printme; /* avoid warning */
|
|
||||||
lua_pushinteger( L, 1 );
|
|
||||||
lua_pushinteger( L, 2 );
|
|
||||||
moon_defobject( L, "B", sizeof( B ), B_methods, 2 );
|
|
||||||
lua_pushinteger( L, 1 );
|
|
||||||
lua_pushinteger( L, 2 );
|
|
||||||
moon_defobject( L, "C", sizeof( C ), C_methods, 2 );
|
|
||||||
moon_defobject( L, "D", sizeof( D ), D_methods, 0 );
|
|
||||||
/* Add a type cast from a C object to the embedded D object. The
|
|
||||||
* cast is executed automatically during moon_checkobject. */
|
|
||||||
moon_defcast( L, "C", "D", C_to_D );
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
luaL_register( L, "objex", objex_funcs );
|
|
||||||
#else
|
|
||||||
luaL_newlib( L, objex_funcs );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <lua.h>
|
|
||||||
#include <lualib.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
#include "plugin.h"
|
|
||||||
#include "moon_dlfix.h"
|
|
||||||
|
|
||||||
int plugin_main( void ) {
|
|
||||||
lua_State* L = luaL_newstate();
|
|
||||||
luaL_openlibs( L );
|
|
||||||
#if 0
|
|
||||||
MOON_DLFIX();
|
|
||||||
#endif
|
|
||||||
if( luaL_dofile( L, "test.lua" ) ) {
|
|
||||||
fprintf( stderr, "%s\n", lua_tostring( L, 1 ) );
|
|
||||||
lua_close( L );
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
lua_close( L );
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#ifndef PLUGIN_H_
|
|
||||||
#define PLUGIN_H_
|
|
||||||
|
|
||||||
#define PLUGIN "plugin_main"
|
|
||||||
typedef int (*plugin)( void );
|
|
||||||
|
|
||||||
#endif /* PLUGIN_H_ */
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#define _GNU_SOURCE
|
|
||||||
#include "moon_dlfix.h"
|
|
||||||
|
|
||||||
/* declaration of lua_State as an opaque type */
|
|
||||||
struct lua_State;
|
|
||||||
typedef struct lua_State lua_State;
|
|
||||||
|
|
||||||
#ifndef EXPORT
|
|
||||||
#define EXPORT extern
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EXPORT int luaopen_sofix( lua_State* L ) {
|
|
||||||
(void)L;
|
|
||||||
MOON_DLFIX();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
#include <lua.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "moon.h"
|
|
||||||
|
|
||||||
static int somefunc( lua_State* L ) {
|
|
||||||
moon_stack_assert( L, "s", "ds", "t" );
|
|
||||||
lua_pushinteger( L, lua_gettop( L ) );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int luaopen_stkex( lua_State* L ) {
|
|
||||||
luaL_Reg const stkex_funcs[] = {
|
|
||||||
{ "somefunc", somefunc },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
luaL_register( L, "stkex", stkex_funcs );
|
|
||||||
#else
|
|
||||||
luaL_newlib( L, stkex_funcs );
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
#!/usr/bin/lua
|
|
||||||
|
|
||||||
package.cpath = "./?.so;../?.so;.\\?.dll;..\\?.dll"
|
|
||||||
require( "sofix" )
|
|
||||||
|
|
||||||
local objex = require( "objex" )
|
|
||||||
local flgex = require( "flgex" )
|
|
||||||
local stkex = require( "stkex" )
|
|
||||||
|
|
||||||
|
|
||||||
print( _VERSION )
|
|
||||||
do
|
|
||||||
print( ("="):rep( 70 ) )
|
|
||||||
print( "[ objex test ]" )
|
|
||||||
local m = objex.getAmethods()
|
|
||||||
print( type( m ) )
|
|
||||||
if type( m ) == "table" then
|
|
||||||
for k,v in pairs( m ) do
|
|
||||||
print( k, v )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local a = objex.newA()
|
|
||||||
print( a, a.tag )
|
|
||||||
a:printme()
|
|
||||||
local b = a.b
|
|
||||||
print( a.b, b, a.c, b.f )
|
|
||||||
b.f = 1.0
|
|
||||||
print( pcall( function() b:printme() end ) )
|
|
||||||
a:printme()
|
|
||||||
a:switch()
|
|
||||||
print( pcall( function() b:printme() end ) )
|
|
||||||
print( a, a.tag )
|
|
||||||
a:printme()
|
|
||||||
local c = a.c
|
|
||||||
print( a.c, c, a.b )
|
|
||||||
c:printme()
|
|
||||||
local d = c.d
|
|
||||||
print( c.d, d, d.x, d.y )
|
|
||||||
d:printme()
|
|
||||||
d.x = 5
|
|
||||||
d.y = 10
|
|
||||||
print( d, d.x, d.y )
|
|
||||||
d:printme()
|
|
||||||
a:switch()
|
|
||||||
print( pcall( d.printme, d ) )
|
|
||||||
a:switch()
|
|
||||||
d:printme()
|
|
||||||
c:close()
|
|
||||||
print( pcall( d.printme, d ) )
|
|
||||||
local d2 = objex.getD()
|
|
||||||
print( d2, d2.x, d2.y )
|
|
||||||
d2:printme()
|
|
||||||
local d3 = objex.makeD( 100, 200 )
|
|
||||||
print( d3, d3.x, d3.y )
|
|
||||||
d3:printme()
|
|
||||||
local d4 = objex.newD()
|
|
||||||
print( d4, d4.x, d4.y )
|
|
||||||
d4:printme()
|
|
||||||
local c2 = objex.newC()
|
|
||||||
c2.d.x = 22
|
|
||||||
c2.d.y = 44
|
|
||||||
d2.x = 4
|
|
||||||
d2.y = 8
|
|
||||||
print( c2 )
|
|
||||||
c2:printme()
|
|
||||||
c2.d = d2
|
|
||||||
c2:printme()
|
|
||||||
c2:printmeD()
|
|
||||||
d2:printme()
|
|
||||||
local methods = objex.derive( "Derived", "D" )
|
|
||||||
function methods:func( ... )
|
|
||||||
print( self, self.a, ... )
|
|
||||||
end
|
|
||||||
local function makeDerived()
|
|
||||||
local d = objex.newD()
|
|
||||||
d.a = "a"
|
|
||||||
return objex.downcast( d, "Derived" )
|
|
||||||
end
|
|
||||||
local x = makeDerived()
|
|
||||||
x.x = 1
|
|
||||||
x.y = 2
|
|
||||||
x:printme()
|
|
||||||
x:vcall( 1, 2, 3 )
|
|
||||||
end
|
|
||||||
collectgarbage()
|
|
||||||
|
|
||||||
|
|
||||||
do
|
|
||||||
print( ("="):rep( 70 ) )
|
|
||||||
print( "[ flgex test ]" )
|
|
||||||
local m = flgex.getXmethods()
|
|
||||||
print( type( m ) )
|
|
||||||
if type( m ) == "table" then
|
|
||||||
for k,v in pairs( m ) do
|
|
||||||
print( k, v )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local flags = flgex.NULL + flgex.ONE + flgex.TWO
|
|
||||||
print( flags )
|
|
||||||
--[[
|
|
||||||
print( "bitops work(1):", flgex.NULL | flgex.ONE | flgex.TWO == flags )
|
|
||||||
print( "bitops work(2):", flags & ~flgex.ONE == flgex.TWO )
|
|
||||||
--]]
|
|
||||||
print( "flags contains flgex.ONE?", flags( flgex.ONE ) )
|
|
||||||
print( "flags contains flgex.TWO?", flags( flgex.TWO ) )
|
|
||||||
flags = flags - flgex.ONE
|
|
||||||
print( "flags contains flgex.ONE?", flags( flgex.ONE ) )
|
|
||||||
print( "flags contains flgex.TWO?", flags( flgex.TWO ) )
|
|
||||||
flags = flags - flgex.TWO
|
|
||||||
print( "flags contains flgex.ONE?", flags( flgex.ONE ) )
|
|
||||||
print( "flags contains flgex.TWO?", flags( flgex.TWO ) )
|
|
||||||
print( "same and identical:", flags == flgex.NULL, flags, flgex.NULL )
|
|
||||||
flags = (flgex.THREE + flgex.FOUR) - flgex.FOUR
|
|
||||||
print( "same but not identical:", flags == flgex.THREE, flags, flgex.THREE )
|
|
||||||
print( "better error message for mismatched types:" )
|
|
||||||
print( pcall( function() local wrong = flgex.ONE + flgex.THREE end ) )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
do
|
|
||||||
print( ("="):rep( 70 ) )
|
|
||||||
print( "[ stkex test ]" )
|
|
||||||
print( pcall( stkex.somefunc, "hello", 123, {} ) )
|
|
||||||
print()
|
|
||||||
print( pcall( stkex.somefunc, "hello", "world", {} ) )
|
|
||||||
print()
|
|
||||||
print( pcall( stkex.somefunc, {} ) )
|
|
||||||
print()
|
|
||||||
print( pcall( stkex.somefunc, true ) )
|
|
||||||
print()
|
|
||||||
print( pcall( stkex.somefunc, "hel\001lo\n", nil, {} ) )
|
|
||||||
print()
|
|
||||||
print( pcall( stkex.somefunc, nil, nil, nil ) )
|
|
||||||
end
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,237 +0,0 @@
|
|||||||
/* Copyright 2013-2016 Philipp Janda <siffiejoe@gmx.net>
|
|
||||||
*
|
|
||||||
* You may do anything with this work that copyright law would normally
|
|
||||||
* restrict, so long as you retain the above notice(s) and this license
|
|
||||||
* in all redistributed copies and derived works. There is no warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MOON_H_
|
|
||||||
#define MOON_H_
|
|
||||||
|
|
||||||
/* file: moon.h
|
|
||||||
* Utility functions/macros for binding C code to Lua.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#if defined(__cplusplus) && !defined(MOON_LUA_CPP)
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
#include <lua.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
#if defined(__cplusplus) && !defined(MOON_LUA_CPP)
|
|
||||||
}
|
|
||||||
#define MOON_LLINKAGE_BEGIN \
|
|
||||||
extern "C" \
|
|
||||||
{
|
|
||||||
#define MOON_LLINKAGE_END }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* use default linkage for functions to pass to Lua */
|
|
||||||
#ifndef MOON_LLINKAGE_BEGIN
|
|
||||||
#define MOON_LLINKAGE_BEGIN
|
|
||||||
#define MOON_LLINKAGE_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MOON_VERSION (300)
|
|
||||||
#define MOON_VERSION_MAJOR (MOON_VERSION / 100)
|
|
||||||
#define MOON_VERSION_MINOR (MOON_VERSION - (MOON_VERSION_MAJOR * 100))
|
|
||||||
|
|
||||||
/* fake CLANG feature detection on other compilers */
|
|
||||||
#ifndef __has_attribute
|
|
||||||
#define __has_attribute(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* platform independent attributes for exporting/importing functions
|
|
||||||
* from shared libraries */
|
|
||||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
|
||||||
#ifndef MOON_LOCAL
|
|
||||||
#define MOON_LOCAL
|
|
||||||
#endif
|
|
||||||
#ifndef MOON_EXPORT
|
|
||||||
#define MOON_EXPORT __declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
#ifndef MOON_IMPORT
|
|
||||||
#define MOON_IMPORT __declspec(dllimport)
|
|
||||||
#endif
|
|
||||||
#elif (defined(__GNUC__) && __GNUC__ >= 4) || __has_attribute(__visibility__)
|
|
||||||
#ifndef MOON_LOCAL
|
|
||||||
#define MOON_LOCAL __attribute__((__visibility__("hidden")))
|
|
||||||
#endif
|
|
||||||
#ifndef MOON_EXPORT
|
|
||||||
#define MOON_EXPORT __attribute__((__visibility__("default")))
|
|
||||||
#endif
|
|
||||||
#ifndef MOON_IMPORT
|
|
||||||
#define MOON_IMPORT __attribute__((__visibility__("default")))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MOON_LOCAL
|
|
||||||
#define MOON_LOCAL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MOON_EXPORT
|
|
||||||
#define MOON_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MOON_IMPORT
|
|
||||||
#define MOON_IMPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* handle linking tricks for moon toolkit */
|
|
||||||
#if defined(MOON_PREFIX)
|
|
||||||
/* - change the symbol names of functions to avoid linker conflicts
|
|
||||||
* - moon.c needs to be compiled (and linked) separately
|
|
||||||
*/
|
|
||||||
#if !defined(MOON_API)
|
|
||||||
/* the following is fine for static linking moon.c to your C module */
|
|
||||||
#define MOON_API MOON_LOCAL
|
|
||||||
#endif
|
|
||||||
#undef MOON_INCLUDE_SOURCE
|
|
||||||
#else /* MOON_PREFIX */
|
|
||||||
/* - make all functions static and include the source (moon.c)
|
|
||||||
* - don't change the symbol names of functions
|
|
||||||
* - moon.c doesn't need to be compiled (and linked) separately
|
|
||||||
*/
|
|
||||||
#define MOON_PREFIX moon
|
|
||||||
#undef MOON_API
|
|
||||||
#if defined(__GNUC__) || __has_attribute(__unused__)
|
|
||||||
#define MOON_API __attribute__((__unused__)) static
|
|
||||||
#else
|
|
||||||
#define MOON_API static
|
|
||||||
#endif
|
|
||||||
#define MOON_INCLUDE_SOURCE
|
|
||||||
#endif /* MOON_PREFIX */
|
|
||||||
|
|
||||||
/* some helper macros */
|
|
||||||
#define MOON_CONCAT_HELPER(a, b) a##b
|
|
||||||
#define MOON_CONCAT(a, b) MOON_CONCAT_HELPER(a, b)
|
|
||||||
#define MOON_STRINGIFY_HELPER(a) #a
|
|
||||||
#define MOON_STRINGIFY(a) MOON_STRINGIFY_HELPER(a)
|
|
||||||
|
|
||||||
/* make sure all functions can be called using the moon_ prefix, even
|
|
||||||
* if we change the prefix behind the scenes */
|
|
||||||
#define moon_defobject MOON_CONCAT(MOON_PREFIX, _defobject)
|
|
||||||
#define moon_newobject MOON_CONCAT(MOON_PREFIX, _newobject)
|
|
||||||
#define moon_newpointer MOON_CONCAT(MOON_PREFIX, _newpointer)
|
|
||||||
#define moon_newfield MOON_CONCAT(MOON_PREFIX, _newfield)
|
|
||||||
#define moon_getmethods MOON_CONCAT(MOON_PREFIX, _getmethods)
|
|
||||||
#define moon_killobject MOON_CONCAT(MOON_PREFIX, _killobject)
|
|
||||||
#define moon_defcast MOON_CONCAT(MOON_PREFIX, _defcast)
|
|
||||||
#define moon_checkobject MOON_CONCAT(MOON_PREFIX, _checkobject)
|
|
||||||
#define moon_testobject MOON_CONCAT(MOON_PREFIX, _testobject)
|
|
||||||
#define moon_derive MOON_CONCAT(MOON_PREFIX, _derive)
|
|
||||||
#define moon_downcast MOON_CONCAT(MOON_PREFIX, _downcast)
|
|
||||||
#define moon_checkint MOON_CONCAT(MOON_PREFIX, _checkint)
|
|
||||||
#define moon_optint MOON_CONCAT(MOON_PREFIX, _optint)
|
|
||||||
#define moon_atexit MOON_CONCAT(MOON_PREFIX, _atexit)
|
|
||||||
#define moon_setuvfield MOON_CONCAT(MOON_PREFIX, _setuvfield)
|
|
||||||
#define moon_getuvfield MOON_CONCAT(MOON_PREFIX, _getuvfield)
|
|
||||||
#define moon_getcache MOON_CONCAT(MOON_PREFIX, _getcache)
|
|
||||||
#define moon_stack_ MOON_CONCAT(MOON_PREFIX, _stack_)
|
|
||||||
#define moon_stack_assert_ MOON_CONCAT(MOON_PREFIX, _stack_assert_)
|
|
||||||
|
|
||||||
/* all objects defined via moon_defobject share a common header of the
|
|
||||||
* following type: */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned char flags;
|
|
||||||
unsigned char cleanup_offset;
|
|
||||||
unsigned char vcheck_offset;
|
|
||||||
unsigned char object_offset;
|
|
||||||
} moon_object_header;
|
|
||||||
|
|
||||||
/* flag values in moon_object_header: */
|
|
||||||
#define MOON_OBJECT_IS_VALID 0x01u
|
|
||||||
#define MOON_OBJECT_IS_POINTER 0x02u
|
|
||||||
|
|
||||||
/* function pointer type for "casts" */
|
|
||||||
typedef void *(*moon_object_cast)(void *);
|
|
||||||
|
|
||||||
/* function pointer type for destructors */
|
|
||||||
typedef void (*moon_object_destructor)(void *);
|
|
||||||
|
|
||||||
/* additional Lua API functions in this toolkit */
|
|
||||||
MOON_API void moon_defobject(lua_State *L, char const *tname,
|
|
||||||
size_t sz, luaL_Reg const *methods,
|
|
||||||
int nup);
|
|
||||||
MOON_API void *moon_newobject(lua_State *L, char const *tname,
|
|
||||||
moon_object_destructor destructor);
|
|
||||||
MOON_API void **moon_newpointer(lua_State *L, char const *tname,
|
|
||||||
moon_object_destructor destructor);
|
|
||||||
MOON_API void **moon_newfield(lua_State *L, char const *tname,
|
|
||||||
int idx, int (*isvalid)(void *p),
|
|
||||||
void *p);
|
|
||||||
MOON_API int moon_getmethods(lua_State *L, char const *tname);
|
|
||||||
MOON_API void moon_killobject(lua_State *L, int idx);
|
|
||||||
MOON_API void moon_defcast(lua_State *L, char const *tname1,
|
|
||||||
char const *tname2,
|
|
||||||
moon_object_cast cast);
|
|
||||||
MOON_API void *moon_checkobject(lua_State *L, int idx,
|
|
||||||
char const *tname);
|
|
||||||
MOON_API void *moon_testobject(lua_State *L, int idx,
|
|
||||||
char const *tname);
|
|
||||||
|
|
||||||
MOON_LLINKAGE_BEGIN
|
|
||||||
MOON_API int moon_derive(lua_State *L);
|
|
||||||
MOON_API int moon_downcast(lua_State *L);
|
|
||||||
MOON_LLINKAGE_END
|
|
||||||
|
|
||||||
MOON_API lua_Integer moon_checkint(lua_State *L, int idx,
|
|
||||||
lua_Integer low,
|
|
||||||
lua_Integer high);
|
|
||||||
MOON_API lua_Integer moon_optint(lua_State *L, int idx,
|
|
||||||
lua_Integer low, lua_Integer high,
|
|
||||||
lua_Integer def);
|
|
||||||
MOON_API int *moon_atexit(lua_State *L, lua_CFunction func);
|
|
||||||
MOON_API int moon_getuvfield(lua_State *L, int i, char const *key);
|
|
||||||
MOON_API void moon_setuvfield(lua_State *L, int i, char const *key);
|
|
||||||
MOON_API void moon_getcache(lua_State *L, int index);
|
|
||||||
MOON_API void moon_stack_(lua_State *L, char const *file, int line,
|
|
||||||
char const *func);
|
|
||||||
MOON_API void moon_stack_assert_(lua_State *L, char const *file,
|
|
||||||
int line, char const *func, ...);
|
|
||||||
|
|
||||||
/* some debugging macros */
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
|
|
||||||
defined(__GNUC__) || defined(__clang__)
|
|
||||||
#define moon_stack_assert(L, ...) \
|
|
||||||
moon_stack_assert_(L, __FILE__, __LINE__, __func__, __VA_ARGS__, (char const *)NULL)
|
|
||||||
#define moon_stack(L) \
|
|
||||||
moon_stack_(L, __FILE__, __LINE__, __func__)
|
|
||||||
#elif defined(_MSC_VER) && _MSC_VER >= 1100L
|
|
||||||
#define moon_stack_assert(L, ...) \
|
|
||||||
moon_stack_assert_(L, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__, (char const *)NULL)
|
|
||||||
#define moon_stack(L) \
|
|
||||||
moon_stack_(L, __FILE__, __LINE__, __FUNCTION__)
|
|
||||||
#else
|
|
||||||
#error preprocessor does not support variadic macros
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define moon_stack(L) ((void)(0))
|
|
||||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
|
|
||||||
(defined(_MSC_VER) && _MSC_VER >= 1100L) || \
|
|
||||||
defined(__GNUC__) || defined(__clang__)
|
|
||||||
#define moon_stack_assert(...) ((void)0)
|
|
||||||
#else
|
|
||||||
#error preprocessor does not support variadic macros
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Lua version compatibility is out of scope for this library, so only
|
|
||||||
* compatibility functions needed for the implementation are provided.
|
|
||||||
* Consider using the Compat-5.3 project which provides backports of
|
|
||||||
* many Lua 5.3 C API functions for Lua 5.1 and 5.2.
|
|
||||||
*/
|
|
||||||
#if LUA_VERSION_NUM < 502
|
|
||||||
MOON_API int moon_absindex(lua_State *L, int idx);
|
|
||||||
#else
|
|
||||||
#define moon_absindex(L, i) lua_absindex((L), (i))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MOON_INCLUDE_SOURCE)
|
|
||||||
#include "moon.c"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MOON_H_ */
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
/* Copyright 2013-2016 Philipp Janda <siffiejoe@gmx.net>
|
|
||||||
*
|
|
||||||
* You may do anything with this work that copyright law would normally
|
|
||||||
* restrict, so long as you retain the above notice(s) and this license
|
|
||||||
* in all redistributed copies and derived works. There is no warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MOON_DLFIX_H_
|
|
||||||
#define MOON_DLFIX_H_
|
|
||||||
|
|
||||||
/* Provides a C function macro that tries to reopen the Lua library
|
|
||||||
* in global mode, so that C extension modules do not have to be
|
|
||||||
* relinked for Lua VMs in shared libraries.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* enable/disable debug output */
|
|
||||||
#if 0
|
|
||||||
#include <stdio.h>
|
|
||||||
#define MOON_DLFIX_DBG(_a) (printf _a)
|
|
||||||
#else
|
|
||||||
#define MOON_DLFIX_DBG(_a) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* detect some form of UNIX, so that unistd.h can be included to
|
|
||||||
* use other feature macros */
|
|
||||||
#if defined(unix) || defined(__unix) || defined(__unix__) || \
|
|
||||||
defined(__TOS_AIX__) || defined(_SYSTYPE_BSD) || \
|
|
||||||
(defined(__APPLE__) && defined(__MACH__)) || \
|
|
||||||
defined(HAVE_UNISTD_H)
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
/* check for minimum POSIX version that specifies dlopen etc. */
|
|
||||||
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || \
|
|
||||||
defined(HAVE_DLFCN_H)
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
/* check for the existence of the RTLD_NOLOAD flag
|
|
||||||
* - GLIBC has it (since 2.2)
|
|
||||||
* - FreeBSD has it
|
|
||||||
* - ...
|
|
||||||
*/
|
|
||||||
#ifdef RTLD_NOLOAD
|
|
||||||
|
|
||||||
/* Lua VM library names to try
|
|
||||||
* Most of them require the dev-package to be installed,
|
|
||||||
* but guessing the real library names for multiple distros
|
|
||||||
* is pretty difficult ...
|
|
||||||
* If the library is not in the default search path you can
|
|
||||||
* set LD_LIBRARY_PATH, or use MOON_DLFIX_LIBNAME to specify
|
|
||||||
* an absolute path to the library.
|
|
||||||
*/
|
|
||||||
static char const *const moon_dlfix_lib_names[] = {
|
|
||||||
/* you can define your own custom name via compiler define: */
|
|
||||||
#ifdef MOON_DLFIX_LIBNAME
|
|
||||||
MOON_DLFIX_LIBNAME,
|
|
||||||
#endif /* custom Lua library name */
|
|
||||||
"liblua5.4.so", /* Lua 5.4, Debian/Ubuntu naming */
|
|
||||||
"liblua5.4.so.0", /* same with common SONAME */
|
|
||||||
"liblua54.so",
|
|
||||||
"liblua5.3.so", /* Lua 5.3, Debian/Ubuntu naming */
|
|
||||||
"liblua5.3.so.0", /* same with common SONAME */
|
|
||||||
"liblua53.so",
|
|
||||||
"liblua5.2.so", /* Lua 5.2, Debian/Ubuntu naming */
|
|
||||||
"liblua5.2.so.0", /* same with common SONAME */
|
|
||||||
"liblua52.so",
|
|
||||||
"liblua.so", /* default name from Lua's makefile */
|
|
||||||
"liblua5.1.so", /* Lua 5.1, Debian/Ubuntu naming */
|
|
||||||
"liblua5.1.so.0", /* same with common SONAME */
|
|
||||||
"liblua51.so",
|
|
||||||
"libluajit-5.1.so", /* LuaJIT default name */
|
|
||||||
"libluajit-5.1.so.2", /* common SONAME */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* On some OSes we can iterate over all loaded libraries to
|
|
||||||
* find the Lua shared object.
|
|
||||||
*/
|
|
||||||
#if defined(__linux__) && defined(_GNU_SOURCE)
|
|
||||||
#define MOON_DLFIX_DL_ITERATE_PHDR
|
|
||||||
#include <link.h>
|
|
||||||
#endif /* Linux with dl_iterate_phdr() function */
|
|
||||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || \
|
|
||||||
defined(__NetBSD__) || defined(__OpenBSD__)
|
|
||||||
#define MOON_DLFIX_DL_ITERATE_PHDR
|
|
||||||
#include <link.h>
|
|
||||||
#endif /* BSDs with dl_iterate_phdr() function */
|
|
||||||
|
|
||||||
#if !defined(MOON_DLFIX_FIND) && \
|
|
||||||
defined(MOON_DLFIX_DL_ITERATE_PHDR)
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef MOON_DLFIX_LIBPREFIX
|
|
||||||
#define MOON_DLFIX_LIBPREFIX "liblua"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int moon_dlfix_cb(struct dl_phdr_info *info, size_t size,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
int *found = data;
|
|
||||||
void *dl = dlopen(info->dlpi_name, RTLD_LAZY);
|
|
||||||
(void)size;
|
|
||||||
MOON_DLFIX_DBG(("Checking ELF object '%s'.\n", info->dlpi_name));
|
|
||||||
if (dl)
|
|
||||||
{
|
|
||||||
if (dlsym(dl, "lua_gettop"))
|
|
||||||
{
|
|
||||||
MOON_DLFIX_DBG(("'%s' does have Lua symbols.\n", info->dlpi_name));
|
|
||||||
/* the Lua API could be in a dependency, so test the library
|
|
||||||
* name for "liblua" */
|
|
||||||
char const *libname = strrchr(info->dlpi_name, '/');
|
|
||||||
if (libname)
|
|
||||||
++libname; /* skip slash */
|
|
||||||
else
|
|
||||||
libname = info->dlpi_name;
|
|
||||||
if (0 == strncmp(libname, MOON_DLFIX_LIBPREFIX,
|
|
||||||
sizeof(MOON_DLFIX_LIBPREFIX) - 1))
|
|
||||||
{
|
|
||||||
void *dl2 = dlopen(info->dlpi_name,
|
|
||||||
RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD);
|
|
||||||
if (dl2)
|
|
||||||
{
|
|
||||||
MOON_DLFIX_DBG(("Found and fixed Lua SO!\n"));
|
|
||||||
dlclose(dl2);
|
|
||||||
*found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dlclose(dl);
|
|
||||||
}
|
|
||||||
return *found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int moon_dlfix_find(void)
|
|
||||||
{
|
|
||||||
int found = 0;
|
|
||||||
MOON_DLFIX_DBG(("Iterating all loaded ELF objects ...\n"));
|
|
||||||
return dl_iterate_phdr(moon_dlfix_cb, &found);
|
|
||||||
}
|
|
||||||
#define MOON_DLFIX_FIND() (moon_dlfix_find())
|
|
||||||
#endif /* has dl_iterate_phdr() function */
|
|
||||||
|
|
||||||
#if !defined(MOON_DLFIX_FIND)
|
|
||||||
/* dummy definition (always returns failure) */
|
|
||||||
#define MOON_DLFIX_FIND() (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Try to iterate all loaded shared libraries using a platform-
|
|
||||||
* specific way to find a loaded Lua shared library.
|
|
||||||
* If that fails, try a list of common library names.
|
|
||||||
* In all cases reopen the Lua library using RTLD_GLOBAL and
|
|
||||||
* RTLD_NOLOAD.
|
|
||||||
*/
|
|
||||||
#define MOON_DLFIX() \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (!MOON_DLFIX_FIND()) \
|
|
||||||
{ \
|
|
||||||
unsigned i = 0; \
|
|
||||||
MOON_DLFIX_DBG(("Trying some common Lua library names ...\n")); \
|
|
||||||
for (; i < sizeof(moon_dlfix_lib_names) / sizeof(*moon_dlfix_lib_names); ++i) \
|
|
||||||
{ \
|
|
||||||
void *dl = dlopen(moon_dlfix_lib_names[i], RTLD_LAZY | RTLD_GLOBAL | RTLD_NOLOAD); \
|
|
||||||
MOON_DLFIX_DBG(("Trying '%s'.\n", moon_dlfix_lib_names[i])); \
|
|
||||||
if (dl) \
|
|
||||||
{ \
|
|
||||||
MOON_DLFIX_DBG(("Fixed Lua SO.\n")); \
|
|
||||||
dlclose(dl); \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif /* has RTLD_NOLOAD */
|
|
||||||
#endif /* has dlfcn.h */
|
|
||||||
#endif /* has unistd.h */
|
|
||||||
|
|
||||||
/* define fallback */
|
|
||||||
#ifndef MOON_DLFIX
|
|
||||||
#define MOON_DLFIX() \
|
|
||||||
(MOON_DLFIX_DBG(("moon_dlfix functionality not available!\n")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MOON_DLFIX_H_ */
|
|
||||||
@ -1,160 +0,0 @@
|
|||||||
/* Copyright 2013-2015 Philipp Janda <siffiejoe@gmx.net>
|
|
||||||
*
|
|
||||||
* You may do anything with this work that copyright law would normally
|
|
||||||
* restrict, so long as you retain the above notice(s) and this license
|
|
||||||
* in all redistributed copies and derived works. There is no warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* this include file is a macro file which could be included
|
|
||||||
* multiple times with different settings.
|
|
||||||
*/
|
|
||||||
#include "moon.h"
|
|
||||||
|
|
||||||
/* "parameter checking" */
|
|
||||||
#ifndef MOON_FLAG_NAME
|
|
||||||
#error MOON_FLAG_NAME is not defined
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MOON_FLAG_TYPE
|
|
||||||
#error MOON_FLAG_TYPE is not defined
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MOON_FLAG_SUFFIX
|
|
||||||
#error MOON_FLAG_SUFFIX is not defined
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MOON_FLAG_ADD MOON_CONCAT(moon_flag_add_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_SUB MOON_CONCAT(moon_flag_sub_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_CALL MOON_CONCAT(moon_flag_call_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_AND MOON_CONCAT(moon_flag_and_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_NOT MOON_CONCAT(moon_flag_not_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_EQ MOON_CONCAT(moon_flag_eq_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_DEF MOON_CONCAT(moon_flag_def_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_NEW MOON_CONCAT(moon_flag_new_, MOON_FLAG_SUFFIX)
|
|
||||||
#define MOON_FLAG_GET MOON_CONCAT(moon_flag_get_, MOON_FLAG_SUFFIX)
|
|
||||||
#ifndef MOON_FLAG_EQMETHOD
|
|
||||||
#define MOON_FLAG_EQMETHOD(a, b) ((a) == (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void MOON_FLAG_NEW(lua_State *L, MOON_FLAG_TYPE v)
|
|
||||||
{
|
|
||||||
#ifdef MOON_FLAG_USECACHE
|
|
||||||
luaL_checkstack(L, 5, MOON_STRINGIFY(MOON_FLAG_NEW));
|
|
||||||
luaL_getmetatable(L, MOON_FLAG_NAME);
|
|
||||||
if (!lua_istable(L, -1))
|
|
||||||
luaL_error(L, "no metatable for type '%s' defined", MOON_FLAG_NAME);
|
|
||||||
moon_getcache(L, -1);
|
|
||||||
lua_pushnumber(L, (lua_Number)v);
|
|
||||||
lua_rawget(L, -2);
|
|
||||||
if (lua_isnil(L, -1))
|
|
||||||
{
|
|
||||||
lua_pop(L, 1);
|
|
||||||
#endif
|
|
||||||
*(MOON_FLAG_TYPE *)moon_newobject(L, MOON_FLAG_NAME, 0) = v;
|
|
||||||
#ifdef MOON_FLAG_USECACHE
|
|
||||||
lua_pushnumber(L, (lua_Number)v);
|
|
||||||
lua_pushvalue(L, -2);
|
|
||||||
lua_rawset(L, -4);
|
|
||||||
}
|
|
||||||
lua_replace(L, -3);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static MOON_FLAG_TYPE MOON_FLAG_GET(lua_State *L, int index)
|
|
||||||
{
|
|
||||||
return *(MOON_FLAG_TYPE *)moon_checkobject(L, index, MOON_FLAG_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef MOON_FLAG_NOBITOPS
|
|
||||||
MOON_LLINKAGE_BEGIN
|
|
||||||
static int MOON_FLAG_ADD(lua_State *L)
|
|
||||||
{
|
|
||||||
MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(*a | *b));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int MOON_FLAG_SUB(lua_State *L)
|
|
||||||
{
|
|
||||||
MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(*a & ~(*b)));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int MOON_FLAG_CALL(lua_State *L)
|
|
||||||
{
|
|
||||||
MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
|
|
||||||
lua_pushboolean(L, !(~(*a) & (*b)));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#if LUA_VERSION_NUM > 502
|
|
||||||
static int MOON_FLAG_AND(lua_State *L)
|
|
||||||
{
|
|
||||||
MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(*a & *b));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int MOON_FLAG_NOT(lua_State *L)
|
|
||||||
{
|
|
||||||
MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_NEW(L, (MOON_FLAG_TYPE)(~*a));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
MOON_LLINKAGE_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MOON_FLAG_NORELOPS
|
|
||||||
MOON_LLINKAGE_BEGIN
|
|
||||||
static int MOON_FLAG_EQ(lua_State *L)
|
|
||||||
{
|
|
||||||
MOON_FLAG_TYPE *a = (MOON_FLAG_TYPE *)moon_checkobject(L, 1, MOON_FLAG_NAME);
|
|
||||||
MOON_FLAG_TYPE *b = (MOON_FLAG_TYPE *)moon_checkobject(L, 2, MOON_FLAG_NAME);
|
|
||||||
lua_pushboolean(L, MOON_FLAG_EQMETHOD(*a, *b));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
MOON_LLINKAGE_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void MOON_FLAG_DEF(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_Reg const methods[] = {
|
|
||||||
#ifndef MOON_FLAG_NOBITOPS
|
|
||||||
{"__add", MOON_FLAG_ADD},
|
|
||||||
{"__sub", MOON_FLAG_SUB},
|
|
||||||
{"__call", MOON_FLAG_CALL},
|
|
||||||
#if LUA_VERSION_NUM > 502
|
|
||||||
{"__band", MOON_FLAG_AND},
|
|
||||||
{"__bor", MOON_FLAG_ADD},
|
|
||||||
{"__bnot", MOON_FLAG_NOT},
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifndef MOON_FLAG_NORELOPS
|
|
||||||
{"__eq", MOON_FLAG_EQ},
|
|
||||||
#endif
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
moon_defobject(L, MOON_FLAG_NAME, sizeof(MOON_FLAG_TYPE),
|
|
||||||
methods, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef MOON_FLAG_ADD
|
|
||||||
#undef MOON_FLAG_SUB
|
|
||||||
#undef MOON_FLAG_CALL
|
|
||||||
#undef MOON_FLAG_AND
|
|
||||||
#undef MOON_FLAG_NOT
|
|
||||||
#undef MOON_FLAG_EQ
|
|
||||||
#undef MOON_FLAG_NEW
|
|
||||||
#undef MOON_FLAG_DEF
|
|
||||||
#undef MOON_FLAG_GET
|
|
||||||
|
|
||||||
#undef MOON_FLAG_NAME
|
|
||||||
#undef MOON_FLAG_TYPE
|
|
||||||
#undef MOON_FLAG_SUFFIX
|
|
||||||
#undef MOON_FLAG_NOBITOPS
|
|
||||||
#undef MOON_FLAG_NORELOPS
|
|
||||||
#undef MOON_FLAG_USECACHE
|
|
||||||
#undef MOON_FLAG_EQMETHOD
|
|
||||||
@ -1,853 +0,0 @@
|
|||||||
#include "math3d-left.h"
|
|
||||||
#include <lua.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
|
|
||||||
// https://github.com/huanzai/math3d
|
|
||||||
|
|
||||||
static void *
|
|
||||||
check_userdata(lua_State *L, int idx)
|
|
||||||
{
|
|
||||||
void *ret = lua_touserdata(L, idx);
|
|
||||||
luaL_argcheck(L, ret != NULL, idx, "Userdata should not be NULL");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lnewvec3(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 tmp;
|
|
||||||
if (lua_isuserdata(L, 1))
|
|
||||||
{
|
|
||||||
struct vector3 *copy = check_userdata(L, 1);
|
|
||||||
tmp = *copy;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp.x = luaL_optnumber(L, 1, 0);
|
|
||||||
tmp.y = luaL_optnumber(L, 2, 0);
|
|
||||||
tmp.z = luaL_optnumber(L, 3, 0);
|
|
||||||
}
|
|
||||||
struct vector3 *vec3 = lua_newuserdata(L, sizeof(*vec3));
|
|
||||||
*vec3 = tmp;
|
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_pack(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *vec3 = check_userdata(L, 1);
|
|
||||||
vec3->x = luaL_optnumber(L, 2, 0);
|
|
||||||
vec3->y = luaL_optnumber(L, 3, 0);
|
|
||||||
vec3->z = luaL_optnumber(L, 4, 0);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_unpack(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *vec3 = check_userdata(L, 1);
|
|
||||||
lua_pushnumber(L, vec3->x);
|
|
||||||
lua_pushnumber(L, vec3->y);
|
|
||||||
lua_pushnumber(L, vec3->z);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_dot(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *a = check_userdata(L, 1);
|
|
||||||
struct vector3 *b = check_userdata(L, 2);
|
|
||||||
float v = vector3_dot(a, b);
|
|
||||||
lua_pushnumber(L, v);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_cross(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct vector3 *a = check_userdata(L, 2);
|
|
||||||
struct vector3 *b = check_userdata(L, 3);
|
|
||||||
vector3_cross(v, a, b);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_vector(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct vector3 *a = check_userdata(L, 2);
|
|
||||||
struct vector3 *b = check_userdata(L, 3);
|
|
||||||
vector3_vector(v, a, b);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_length(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
float len = vector3_length(v);
|
|
||||||
lua_pushnumber(L, len);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_normalize(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
vector3_normalize(v);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_copy(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct vector3 *from = check_userdata(L, 2);
|
|
||||||
*v = *from;
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_tostring(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
lua_pushfstring(L, "[%f, %f, %f]", v->x, v->y, v->z);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_rotation(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct vector3 *from = check_userdata(L, 2);
|
|
||||||
vector3_to_rotation(v, from);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_lerp(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct vector3 *a = check_userdata(L, 2);
|
|
||||||
struct vector3 *b = check_userdata(L, 3);
|
|
||||||
float f = luaL_checknumber(L, 4);
|
|
||||||
vector3_lerp(v, a, b, f);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
create_meta(lua_State *L, luaL_Reg *l, const char *name, lua_CFunction tostring)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
while (l[n].name)
|
|
||||||
++n;
|
|
||||||
lua_newtable(L);
|
|
||||||
lua_createtable(L, 0, n);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
lua_pushcfunction(L, l[i].func);
|
|
||||||
lua_setfield(L, -2, l[i].name);
|
|
||||||
}
|
|
||||||
lua_setfield(L, -2, "__index");
|
|
||||||
lua_pushstring(L, name);
|
|
||||||
lua_setfield(L, -2, "__metatable");
|
|
||||||
lua_pushcfunction(L, tostring);
|
|
||||||
lua_setfield(L, -2, "__tostring");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_transmat(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
matrix44_trans(m, v->x, v->y, v->z);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_scalemat(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
matrix44_scale(m, v->x, v->y, v->z);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_rotmat(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
matrix44_rot(m, v->x, v->y, v->z);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_rotaxis(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
float angle = luaL_checknumber(L, 3);
|
|
||||||
matrix44_rot_axis(m, v, angle);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_mul(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
vector3_mul(v, m);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_mul33(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
vector3_mul33(v, m);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_distAABB(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct vector3 *mins = check_userdata(L, 2);
|
|
||||||
struct vector3 *maxs = check_userdata(L, 3);
|
|
||||||
float d = vector3_distAABB(v, mins, maxs);
|
|
||||||
lua_pushnumber(L, d);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec3_plane(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector3 *v = check_userdata(L, 1);
|
|
||||||
struct plane *p = check_userdata(L, 2);
|
|
||||||
float d = luaL_optnumber(L, 3, 0);
|
|
||||||
plane_init(p, v, d);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
vector3(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_Reg l[] = {
|
|
||||||
{"pack", lvec3_pack},
|
|
||||||
{"unpack", lvec3_unpack},
|
|
||||||
{"dot", lvec3_dot},
|
|
||||||
{"cross", lvec3_cross},
|
|
||||||
{"vector", lvec3_vector},
|
|
||||||
{"length", lvec3_length},
|
|
||||||
{"normalize", lvec3_normalize},
|
|
||||||
{"copy", lvec3_copy},
|
|
||||||
{"rotation", lvec3_rotation},
|
|
||||||
{"lerp", lvec3_lerp},
|
|
||||||
{"transmat", lvec3_transmat},
|
|
||||||
{"scalemat", lvec3_scalemat},
|
|
||||||
{"rotmat", lvec3_rotmat},
|
|
||||||
{"rotaxis", lvec3_rotaxis},
|
|
||||||
{"mul", lvec3_mul},
|
|
||||||
{"mul33", lvec3_mul33},
|
|
||||||
{"plane", lvec3_plane},
|
|
||||||
{"distAABB", lvec3_distAABB},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
create_meta(L, l, "vector3", lvec3_tostring);
|
|
||||||
lua_pushcclosure(L, lnewvec3, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lnewquat(lua_State *L)
|
|
||||||
{
|
|
||||||
if (lua_isuserdata(L, 1))
|
|
||||||
{
|
|
||||||
struct quaternion *tmp = check_userdata(L, 1);
|
|
||||||
struct quaternion *q = lua_newuserdata(L, sizeof(*q));
|
|
||||||
*q = *tmp;
|
|
||||||
}
|
|
||||||
else if lua_isnoneornil (L, 1)
|
|
||||||
{
|
|
||||||
struct quaternion *q = lua_newuserdata(L, sizeof(*q));
|
|
||||||
q->x = 0;
|
|
||||||
q->y = 0;
|
|
||||||
q->z = 0;
|
|
||||||
q->w = 1.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float x = luaL_checknumber(L, 1);
|
|
||||||
float y = luaL_checknumber(L, 2);
|
|
||||||
float z = luaL_checknumber(L, 3);
|
|
||||||
struct quaternion *q = lua_newuserdata(L, sizeof(*q));
|
|
||||||
quaternion_init(q, x, y, z);
|
|
||||||
}
|
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_tostring(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
lua_pushfstring(L, "[%f, %f, %f, %f]", q->x, q->y, q->z, q->w);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_mul(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
struct quaternion *a = check_userdata(L, 2);
|
|
||||||
struct quaternion *b = check_userdata(L, 3);
|
|
||||||
quaternion_mul(q, a, b);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_copy(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *a = check_userdata(L, 1);
|
|
||||||
struct quaternion *b = check_userdata(L, 2);
|
|
||||||
*a = *b;
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_slerp(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
struct quaternion *a = check_userdata(L, 2);
|
|
||||||
struct quaternion *b = check_userdata(L, 3);
|
|
||||||
float t = luaL_checknumber(L, 4);
|
|
||||||
quaternion_slerp(q, a, b, t);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_nslerp(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
struct quaternion *a = check_userdata(L, 2);
|
|
||||||
struct quaternion *b = check_userdata(L, 3);
|
|
||||||
float t = luaL_checknumber(L, 4);
|
|
||||||
quaternion_nslerp(q, a, b, t);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_inverted(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
quaternion_inverted(q);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_matrix(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
union matrix44 *mat = check_userdata(L, 2);
|
|
||||||
matrix44_from_quaternion(mat, q);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_pack(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
q->x = luaL_checknumber(L, 2);
|
|
||||||
q->y = luaL_checknumber(L, 3);
|
|
||||||
q->z = luaL_checknumber(L, 4);
|
|
||||||
q->w = luaL_checknumber(L, 5);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lquat_unpack(lua_State *L)
|
|
||||||
{
|
|
||||||
struct quaternion *q = check_userdata(L, 1);
|
|
||||||
lua_pushnumber(L, q->x);
|
|
||||||
lua_pushnumber(L, q->y);
|
|
||||||
lua_pushnumber(L, q->z);
|
|
||||||
lua_pushnumber(L, q->w);
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
quaternion(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_Reg l[] = {
|
|
||||||
{"mul", lquat_mul},
|
|
||||||
{"copy", lquat_copy},
|
|
||||||
{"pack", lquat_pack},
|
|
||||||
{"unpack", lquat_unpack},
|
|
||||||
{"slerp", lquat_slerp},
|
|
||||||
{"nslerp", lquat_nslerp},
|
|
||||||
{"inverted", lquat_inverted},
|
|
||||||
{"matrix", lquat_matrix},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
create_meta(L, l, "quateraion", lquat_tostring);
|
|
||||||
lua_pushcclosure(L, lnewquat, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lnewmat(lua_State *L)
|
|
||||||
{
|
|
||||||
if (lua_isuserdata(L, 1))
|
|
||||||
{
|
|
||||||
union matrix44 *tmp = check_userdata(L, 1);
|
|
||||||
union matrix44 *mat = lua_newuserdata(L, sizeof(*mat));
|
|
||||||
*mat = *tmp;
|
|
||||||
}
|
|
||||||
else if lua_isnoneornil (L, 1)
|
|
||||||
{
|
|
||||||
union matrix44 *mat = lua_newuserdata(L, sizeof(*mat));
|
|
||||||
matrix44_identity(mat);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float x = luaL_checknumber(L, 1);
|
|
||||||
float y = luaL_checknumber(L, 2);
|
|
||||||
float z = luaL_checknumber(L, 3);
|
|
||||||
union matrix44 *mat = lua_newuserdata(L, sizeof(*mat));
|
|
||||||
matrix44_rot(mat, x, y, z);
|
|
||||||
}
|
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_tostring(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
lua_pushfstring(L, "[(%f, %f, %f, %f) (%f, %f, %f, %f) (%f, %f, %f, %f) (%f, %f, %f, %f)]",
|
|
||||||
m->c[0][0], m->c[0][1], m->c[0][2], m->c[0][3],
|
|
||||||
m->c[1][0], m->c[1][1], m->c[1][2], m->c[1][3],
|
|
||||||
m->c[2][0], m->c[2][1], m->c[2][2], m->c[2][3],
|
|
||||||
m->c[3][0], m->c[3][1], m->c[3][2], m->c[3][3]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_pack(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
m->x[i] = luaL_checknumber(L, 2 + i);
|
|
||||||
}
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_unpack(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
lua_pushnumber(L, m->x[i]);
|
|
||||||
}
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_copy(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
union matrix44 *from = check_userdata(L, 2);
|
|
||||||
*m = *from;
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_identity(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
matrix44_identity(m);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_perspective(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
float l = luaL_checknumber(L, 2);
|
|
||||||
float r = luaL_checknumber(L, 3);
|
|
||||||
float b = luaL_checknumber(L, 4);
|
|
||||||
float t = luaL_checknumber(L, 5);
|
|
||||||
float n = luaL_checknumber(L, 6);
|
|
||||||
float f = luaL_checknumber(L, 7);
|
|
||||||
matrix44_perspective(m, l, r, b, t, n, f);
|
|
||||||
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_ortho(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
float l = luaL_checknumber(L, 2);
|
|
||||||
float r = luaL_checknumber(L, 3);
|
|
||||||
float b = luaL_checknumber(L, 4);
|
|
||||||
float t = luaL_checknumber(L, 5);
|
|
||||||
float n = luaL_checknumber(L, 6);
|
|
||||||
float f = luaL_checknumber(L, 7);
|
|
||||||
matrix44_ortho(m, l, r, b, t, n, f);
|
|
||||||
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_mul(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
union matrix44 *a = check_userdata(L, 2);
|
|
||||||
union matrix44 *b = check_userdata(L, 3);
|
|
||||||
if (b == NULL)
|
|
||||||
{
|
|
||||||
b = a;
|
|
||||||
a = m;
|
|
||||||
}
|
|
||||||
matrix44_mul(m, a, b);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_fastmul43(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
union matrix44 *a = check_userdata(L, 2);
|
|
||||||
union matrix44 *b = check_userdata(L, 3);
|
|
||||||
matrix44_fastmul43(m, a, b);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_transposed(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
matrix44_transposed(m);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_determinant(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
float v = matrix44_determinant(m);
|
|
||||||
lua_pushnumber(L, v);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_inverted(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
union matrix44 *from = check_userdata(L, 2);
|
|
||||||
matrix44_inverted(m, from);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_trans(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
struct vector3 *v = check_userdata(L, 2);
|
|
||||||
matrix44_gettrans(m, v);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_scale(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
struct vector3 *v = check_userdata(L, 2);
|
|
||||||
matrix44_getscale(m, v);
|
|
||||||
lua_settop(L, 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lmat_decompose(lua_State *L)
|
|
||||||
{
|
|
||||||
union matrix44 *m = check_userdata(L, 1);
|
|
||||||
struct vector3 *trans = check_userdata(L, 2);
|
|
||||||
struct vector3 *rot = check_userdata(L, 3);
|
|
||||||
struct vector3 *scale = check_userdata(L, 4);
|
|
||||||
matrix44_decompose(m, trans, rot, scale);
|
|
||||||
lua_settop(L, 4);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
matrix(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_Reg l[] = {
|
|
||||||
{"pack", lmat_pack},
|
|
||||||
{"unpack", lmat_unpack},
|
|
||||||
{"copy", lmat_copy},
|
|
||||||
{"identity", lmat_identity},
|
|
||||||
{"perspective", lmat_perspective},
|
|
||||||
{"ortho", lmat_ortho},
|
|
||||||
{"mul", lmat_mul},
|
|
||||||
{"fastmul43", lmat_fastmul43},
|
|
||||||
{"transposed", lmat_transposed},
|
|
||||||
{"determinant", lmat_determinant},
|
|
||||||
{"inverted", lmat_inverted},
|
|
||||||
{"trans", lmat_trans},
|
|
||||||
{"scale", lmat_scale},
|
|
||||||
{"decompose", lmat_decompose},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
create_meta(L, l, "matrix", lmat_tostring);
|
|
||||||
lua_pushcclosure(L, lnewmat, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lnewvec4(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector4 tmp;
|
|
||||||
if (lua_isuserdata(L, 1))
|
|
||||||
{
|
|
||||||
struct vector4 *copy = check_userdata(L, 1);
|
|
||||||
tmp = *copy;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp.x = luaL_optnumber(L, 1, 0);
|
|
||||||
tmp.y = luaL_optnumber(L, 2, 0);
|
|
||||||
tmp.z = luaL_optnumber(L, 3, 0);
|
|
||||||
tmp.z = luaL_optnumber(L, 4, 1.0);
|
|
||||||
}
|
|
||||||
struct vector4 *vec4 = lua_newuserdata(L, sizeof(*vec4));
|
|
||||||
*vec4 = tmp;
|
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define lvec4_tostring lquat_tostring
|
|
||||||
#define lvec4_copy lquat_copy
|
|
||||||
#define lvec4_pack lquat_pack
|
|
||||||
#define lvec4_unpack lquat_unpack
|
|
||||||
|
|
||||||
static int
|
|
||||||
lvec4_mul(lua_State *L)
|
|
||||||
{
|
|
||||||
struct vector4 *v = check_userdata(L, 1);
|
|
||||||
union matrix44 *m = check_userdata(L, 2);
|
|
||||||
vector4_mul(v, m);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
vector4(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_Reg l[] = {
|
|
||||||
{"copy", lvec4_copy},
|
|
||||||
{"pack", lvec4_pack},
|
|
||||||
{"unpack", lvec4_unpack},
|
|
||||||
{"mul", lvec4_mul},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
create_meta(L, l, "vector4", lvec4_tostring);
|
|
||||||
lua_pushcclosure(L, lnewvec4, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lnewplane(lua_State *L)
|
|
||||||
{
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
if (top == 0)
|
|
||||||
{
|
|
||||||
struct plane *p = lua_newuserdata(L, sizeof(*p));
|
|
||||||
p->normal.x = 0;
|
|
||||||
p->normal.y = 0;
|
|
||||||
p->normal.z = 1;
|
|
||||||
p->dist = 0; // XY plane
|
|
||||||
}
|
|
||||||
else if (top == 1)
|
|
||||||
{
|
|
||||||
struct plane *copy = check_userdata(L, 1);
|
|
||||||
struct plane *p = lua_newuserdata(L, sizeof(*p));
|
|
||||||
*p = *copy;
|
|
||||||
}
|
|
||||||
else if (top == 3)
|
|
||||||
{
|
|
||||||
struct vector3 *a = check_userdata(L, 1);
|
|
||||||
struct vector3 *b = check_userdata(L, 2);
|
|
||||||
struct vector3 *c = check_userdata(L, 3);
|
|
||||||
struct plane *p = lua_newuserdata(L, sizeof(*p));
|
|
||||||
plane_init_dot3(p, a, b, c);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return luaL_error(L, "Invalid new plane");
|
|
||||||
}
|
|
||||||
lua_pushvalue(L, lua_upvalueindex(1));
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lplane_tostring(lua_State *L)
|
|
||||||
{
|
|
||||||
struct plane *p = check_userdata(L, 1);
|
|
||||||
lua_pushfstring(L, "[%f, %f, %f : %f]", p->normal.x, p->normal.x, p->normal.z, p->dist);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lplane_dist(lua_State *L)
|
|
||||||
{
|
|
||||||
struct plane *p = check_userdata(L, 1);
|
|
||||||
struct vector3 *v = check_userdata(L, 2);
|
|
||||||
float d = plane_dist(p, v);
|
|
||||||
lua_pushnumber(L, d);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lplane_copy(lua_State *L)
|
|
||||||
{
|
|
||||||
struct plane *p = check_userdata(L, 1);
|
|
||||||
struct plane *from = check_userdata(L, 2);
|
|
||||||
*p = *from;
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lplane_dot3(lua_State *L)
|
|
||||||
{
|
|
||||||
struct plane *p = check_userdata(L, 1);
|
|
||||||
struct vector3 *a = check_userdata(L, 2);
|
|
||||||
struct vector3 *b = check_userdata(L, 3);
|
|
||||||
struct vector3 *c = check_userdata(L, 4);
|
|
||||||
plane_init_dot3(p, a, b, c);
|
|
||||||
lua_settop(L, 1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
plane(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_Reg l[] = {
|
|
||||||
{"copy", lplane_copy},
|
|
||||||
{"dist", lplane_dist},
|
|
||||||
{"dot3", lplane_dot3},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
create_meta(L, l, "plane", lplane_tostring);
|
|
||||||
lua_pushcclosure(L, lnewplane, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lraytriangle(lua_State *L)
|
|
||||||
{
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
if (top != 6)
|
|
||||||
{
|
|
||||||
return luaL_error(L, "intersection.raytriangle(rayOrig,rayDir,p0,p1,p2,ret)");
|
|
||||||
}
|
|
||||||
struct vector3 *ro = check_userdata(L, 1);
|
|
||||||
struct vector3 *rd = check_userdata(L, 2);
|
|
||||||
struct vector3 *p0 = check_userdata(L, 3);
|
|
||||||
struct vector3 *p1 = check_userdata(L, 4);
|
|
||||||
struct vector3 *p2 = check_userdata(L, 5);
|
|
||||||
struct vector3 *inst = check_userdata(L, 6);
|
|
||||||
if (intersection_raytriangle(ro, rd, p0, p1, p2, inst) == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
lrayAABB(lua_State *L)
|
|
||||||
{
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
if (top != 4)
|
|
||||||
{
|
|
||||||
return luaL_error(L, "intersection.rayAABB(rayOrig,rayDir,mins,maxs)");
|
|
||||||
}
|
|
||||||
struct vector3 *ro = check_userdata(L, 1);
|
|
||||||
struct vector3 *rd = check_userdata(L, 2);
|
|
||||||
struct vector3 *mins = check_userdata(L, 3);
|
|
||||||
struct vector3 *maxs = check_userdata(L, 4);
|
|
||||||
int r = intersection_rayAABB(ro, rd, mins, maxs);
|
|
||||||
lua_pushboolean(L, r);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int luaopen_math3d(lua_State *L)
|
|
||||||
{
|
|
||||||
luaL_checkversion(L);
|
|
||||||
lua_newtable(L);
|
|
||||||
vector3(L);
|
|
||||||
lua_setfield(L, -2, "vector3");
|
|
||||||
quaternion(L);
|
|
||||||
lua_setfield(L, -2, "quaternion");
|
|
||||||
matrix(L);
|
|
||||||
lua_setfield(L, -2, "matrix");
|
|
||||||
vector4(L);
|
|
||||||
lua_setfield(L, -2, "vector4");
|
|
||||||
plane(L);
|
|
||||||
lua_setfield(L, -2, "plane");
|
|
||||||
luaL_Reg l[] = {
|
|
||||||
{"raytriangle", lraytriangle},
|
|
||||||
{"rayAABB", lrayAABB},
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
luaL_newlib(L, l);
|
|
||||||
lua_setfield(L, -2, "intersection");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@ -1,836 +0,0 @@
|
|||||||
// This is a rewrite version (in C) from Horde3D (utMath.h) , http://www.horde3d.org
|
|
||||||
// Math library
|
|
||||||
//
|
|
||||||
// Coordinate system is left-handed with positive y as up axis
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ejoy3d_math_h
|
|
||||||
#define ejoy3d_math_h
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <float.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
struct vector3
|
|
||||||
{
|
|
||||||
float x, y, z;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vector4
|
|
||||||
{
|
|
||||||
float x, y, z, w;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct quaternion
|
|
||||||
{
|
|
||||||
float x, y, z, w;
|
|
||||||
};
|
|
||||||
|
|
||||||
union matrix44
|
|
||||||
{
|
|
||||||
float c[4][4];
|
|
||||||
float x[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plane
|
|
||||||
{
|
|
||||||
struct vector3 normal;
|
|
||||||
float dist;
|
|
||||||
};
|
|
||||||
|
|
||||||
// vector
|
|
||||||
|
|
||||||
static inline float *
|
|
||||||
vector3_array(struct vector3 *v)
|
|
||||||
{
|
|
||||||
return (float *)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float *
|
|
||||||
vector4_array(struct vector4 *v)
|
|
||||||
{
|
|
||||||
return (float *)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
vector3_dot(const struct vector3 *a, const struct vector3 *b)
|
|
||||||
{
|
|
||||||
return a->x * b->x + a->y * b->y + a->z * b->z;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_cross(struct vector3 *v, const struct vector3 *a, const struct vector3 *b)
|
|
||||||
{
|
|
||||||
float x = a->y * b->z - a->z * b->y;
|
|
||||||
float y = a->z * b->x - a->x * b->z;
|
|
||||||
float z = a->x * b->y - a->y * b->x;
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_vector(struct vector3 *v, const struct vector3 *p1, const struct vector3 *p2)
|
|
||||||
{
|
|
||||||
v->x = p1->x - p2->x;
|
|
||||||
v->y = p1->y - p2->y;
|
|
||||||
v->z = p1->z - p2->z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
vector3_length(const struct vector3 *v)
|
|
||||||
{
|
|
||||||
return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_normalize(struct vector3 *v)
|
|
||||||
{
|
|
||||||
float invLen = 1.0f / vector3_length(v);
|
|
||||||
v->x *= invLen;
|
|
||||||
v->y *= invLen;
|
|
||||||
v->z *= invLen;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_to_rotation(struct vector3 *v, const struct vector3 *r)
|
|
||||||
{
|
|
||||||
// Assumes that the unrotated view vector is (0, 0, -1)
|
|
||||||
v->x = v->y = v->z = 0;
|
|
||||||
if (r->y != 0)
|
|
||||||
{
|
|
||||||
v->x = atan2f(r->y, sqrtf(r->x * r->x + r->z * r->z));
|
|
||||||
}
|
|
||||||
if (r->x != 0 || r->z != 0)
|
|
||||||
{
|
|
||||||
v->y = atan2f(-r->x, -r->z);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_lerp(struct vector3 *v, const struct vector3 *a, const struct vector3 *b, float f)
|
|
||||||
{
|
|
||||||
float x = a->x + (b->x - a->x) * f;
|
|
||||||
float y = a->y + (b->y - a->y) * f;
|
|
||||||
float z = a->z + (b->z - a->z) * f;
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// quaternion
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_mul(struct quaternion *q, const struct quaternion *a, const struct quaternion *b)
|
|
||||||
{
|
|
||||||
float x = a->y * b->z - a->z * b->y + b->x * a->w + a->x * b->w;
|
|
||||||
float y = a->z * b->x - a->x * b->z + b->y * a->w + a->y * b->w;
|
|
||||||
float z = a->x * b->y - a->y * b->x + b->z * a->w + a->z * b->w;
|
|
||||||
float w = a->w * b->w - (a->x * b->x + a->y * b->y + a->z * b->z);
|
|
||||||
|
|
||||||
q->x = x;
|
|
||||||
q->y = y;
|
|
||||||
q->z = z;
|
|
||||||
q->w = w;
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_init(struct quaternion *q, float x, float y, float z)
|
|
||||||
{
|
|
||||||
struct quaternion roll = {sinf(x * 0.5f), 0, 0, cosf(x * 0.5f)};
|
|
||||||
struct quaternion pitch = {0, sinf(y * 0.5f), 0, cosf(y * 0.5f)};
|
|
||||||
struct quaternion yaw = {0, 0, sinf(z * 0.5f), cosf(z * 0.5f)};
|
|
||||||
|
|
||||||
// Order: y * x * z
|
|
||||||
quaternion_mul(q, &pitch, &roll);
|
|
||||||
quaternion_mul(q, q, &yaw);
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_slerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
|
|
||||||
{
|
|
||||||
float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
|
|
||||||
if (cosTheta < 0)
|
|
||||||
{
|
|
||||||
cosTheta = -cosTheta;
|
|
||||||
q->x = -b->x;
|
|
||||||
q->y = -b->y;
|
|
||||||
q->z = -b->z;
|
|
||||||
q->w = -b->w;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*q = *b;
|
|
||||||
}
|
|
||||||
float scale0 = 1 - t, scale1 = t;
|
|
||||||
if ((1 - cosTheta) > 0.001f)
|
|
||||||
{
|
|
||||||
// use spherical interpolation
|
|
||||||
float theta = acosf(cosTheta);
|
|
||||||
float sinTheta = sinf(theta);
|
|
||||||
scale0 = sinf((1 - t) * theta) / sinTheta;
|
|
||||||
scale1 = sinf(t * theta) / sinTheta;
|
|
||||||
}
|
|
||||||
|
|
||||||
q->x = a->x * scale0 + q->x * scale1;
|
|
||||||
q->y = a->y * scale0 + q->y * scale1;
|
|
||||||
q->z = a->z * scale0 + q->z * scale1;
|
|
||||||
q->w = a->w * scale0 + q->w * scale1;
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_nslerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
|
|
||||||
{
|
|
||||||
// Normalized linear quaternion interpolation
|
|
||||||
// Note: NLERP is faster than SLERP and commutative but does not yield constant velocity
|
|
||||||
|
|
||||||
float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
|
|
||||||
|
|
||||||
if (cosTheta < 0)
|
|
||||||
{
|
|
||||||
q->x = a->x + (-b->x - a->x) * t;
|
|
||||||
q->y = a->y + (-b->y - a->y) * t;
|
|
||||||
q->z = a->z + (-b->z - a->z) * t;
|
|
||||||
q->w = a->w + (-b->w - a->w) * t;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
q->x = a->x + (b->x - a->x) * t;
|
|
||||||
q->y = a->y + (b->y - a->y) * t;
|
|
||||||
q->z = a->z + (b->z - a->z) * t;
|
|
||||||
q->w = a->w + (b->w - a->w) * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
float invLen = 1.0f / sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
|
|
||||||
|
|
||||||
q->x *= invLen;
|
|
||||||
q->y *= invLen;
|
|
||||||
q->z *= invLen;
|
|
||||||
q->w *= invLen;
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_inverted(struct quaternion *q)
|
|
||||||
{
|
|
||||||
float len = q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
float invLen = -1.0f / len;
|
|
||||||
q->x *= invLen;
|
|
||||||
q->y *= invLen;
|
|
||||||
q->z *= invLen;
|
|
||||||
q->w *= invLen;
|
|
||||||
q->w = -q->w;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
q->x = q->y = q->z = q->w = 0;
|
|
||||||
}
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
// matrix 4*4
|
|
||||||
|
|
||||||
#define C m->c
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_identity(union matrix44 *m)
|
|
||||||
{
|
|
||||||
C[0][0] = 1;
|
|
||||||
C[1][0] = 0;
|
|
||||||
C[2][0] = 0;
|
|
||||||
C[3][0] = 0;
|
|
||||||
C[0][1] = 0;
|
|
||||||
C[1][1] = 1;
|
|
||||||
C[2][1] = 0;
|
|
||||||
C[3][1] = 0;
|
|
||||||
C[0][2] = 0;
|
|
||||||
C[1][2] = 0;
|
|
||||||
C[2][2] = 1;
|
|
||||||
C[3][2] = 0;
|
|
||||||
C[0][3] = 0;
|
|
||||||
C[1][3] = 0;
|
|
||||||
C[2][3] = 0;
|
|
||||||
C[3][3] = 1;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_from_quaternion(union matrix44 *m, const struct quaternion *q)
|
|
||||||
{
|
|
||||||
// Calculate coefficients
|
|
||||||
float x2 = q->x + q->x, y2 = q->y + q->y, z2 = q->z + q->z;
|
|
||||||
float xx = q->x * x2, xy = q->x * y2, xz = q->x * z2;
|
|
||||||
float yy = q->y * y2, yz = q->y * z2, zz = q->z * z2;
|
|
||||||
float wx = q->w * x2, wy = q->w * y2, wz = q->w * z2;
|
|
||||||
|
|
||||||
C[0][0] = 1 - (yy + zz);
|
|
||||||
C[1][0] = xy + wz;
|
|
||||||
C[2][0] = xz - wy;
|
|
||||||
C[3][0] = 0;
|
|
||||||
C[0][1] = xy - wz;
|
|
||||||
C[1][1] = 1 - (xx + zz);
|
|
||||||
C[2][1] = yz + wx;
|
|
||||||
C[3][1] = 0;
|
|
||||||
C[0][2] = xz + wy;
|
|
||||||
C[1][2] = yz - wx;
|
|
||||||
C[2][2] = 1 - (xx + yy);
|
|
||||||
C[3][2] = 0;
|
|
||||||
C[0][3] = 0;
|
|
||||||
C[1][3] = 0;
|
|
||||||
C[2][3] = 0;
|
|
||||||
C[3][3] = 1;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_trans(union matrix44 *m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
C[3][0] = x;
|
|
||||||
C[3][1] = y;
|
|
||||||
C[3][2] = z;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_scale(union matrix44 *m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
C[0][0] = x;
|
|
||||||
C[1][1] = y;
|
|
||||||
C[2][2] = z;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_rot(union matrix44 *m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
// Rotation order: YXZ [* Vector]
|
|
||||||
struct quaternion q;
|
|
||||||
quaternion_init(&q, x, y, z);
|
|
||||||
|
|
||||||
return matrix44_from_quaternion(m, &q);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_rot_axis(union matrix44 *m, const struct vector3 *axis, float angle)
|
|
||||||
{
|
|
||||||
float t = sinf(angle * 0.5f);
|
|
||||||
float x = axis->x * t;
|
|
||||||
float y = axis->y * t;
|
|
||||||
float z = axis->z * t;
|
|
||||||
struct quaternion q = {x, y, z, cosf(angle * 0.5f)};
|
|
||||||
|
|
||||||
return matrix44_from_quaternion(m, &q);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_perspective(union matrix44 *m, float l, float r, float b, float t, float n, float f)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
float *mx = m->x;
|
|
||||||
|
|
||||||
mx[0] = 2 * n / (r - l);
|
|
||||||
mx[5] = 2 * n / (t - b);
|
|
||||||
mx[8] = -(r + l) / (r - l);
|
|
||||||
mx[9] = -(t + b) / (t - b);
|
|
||||||
mx[10] = (f + n) / (f - n);
|
|
||||||
mx[11] = 1;
|
|
||||||
mx[14] = -2 * f * n / (f - n);
|
|
||||||
mx[15] = 0;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_ortho(union matrix44 *m, float l, float r, float b, float t, float n, float f)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
float *mx = m->x;
|
|
||||||
|
|
||||||
mx[0] = 2 / (r - l);
|
|
||||||
mx[5] = 2 / (t - b);
|
|
||||||
mx[10] = 2 / (f - n);
|
|
||||||
mx[12] = -(r + l) / (r - l);
|
|
||||||
mx[13] = -(t + b) / (t - b);
|
|
||||||
mx[14] = -(f + n) / (f - n);
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_fastmul43(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
|
|
||||||
{
|
|
||||||
// Note: m may not be the same as m1 or m2
|
|
||||||
|
|
||||||
const float *m1x = m1->x;
|
|
||||||
const float *m2x = m2->x;
|
|
||||||
float *mx = m->x;
|
|
||||||
|
|
||||||
mx[0] = m1x[0] * m2x[0] + m1x[1] * m2x[4] + m1x[2] * m2x[8];
|
|
||||||
mx[1] = m1x[0] * m2x[1] + m1x[1] * m2x[5] + m1x[2] * m2x[9];
|
|
||||||
mx[2] = m1x[0] * m2x[2] + m1x[1] * m2x[6] + m1x[2] * m2x[10];
|
|
||||||
mx[3] = 0.0f;
|
|
||||||
|
|
||||||
mx[4] = m1x[4] * m2x[0] + m1x[5] * m2x[4] + m1x[6] * m2x[8];
|
|
||||||
mx[5] = m1x[4] * m2x[1] + m1x[5] * m2x[5] + m1x[6] * m2x[9];
|
|
||||||
mx[6] = m1x[4] * m2x[2] + m1x[5] * m2x[6] + m1x[6] * m2x[10];
|
|
||||||
mx[7] = 0.0f;
|
|
||||||
|
|
||||||
mx[8] = m1x[8] * m2x[0] + m1x[9] * m2x[4] + m1x[10] * m2x[8];
|
|
||||||
mx[9] = m1x[8] * m2x[1] + m1x[9] * m2x[5] + m1x[10] * m2x[9];
|
|
||||||
mx[10] = m1x[8] * m2x[2] + m1x[9] * m2x[6] + m1x[10] * m2x[10];
|
|
||||||
mx[11] = 0.0f;
|
|
||||||
|
|
||||||
mx[12] = m1x[12] * m2x[0] + m1x[13] * m2x[4] + m1x[14] * m2x[8] + m1x[15] * m2x[12];
|
|
||||||
mx[13] = m1x[12] * m2x[1] + m1x[13] * m2x[5] + m1x[14] * m2x[9] + m1x[15] * m2x[13];
|
|
||||||
mx[14] = m1x[12] * m2x[1] + m1x[13] * m2x[6] + m1x[14] * m2x[10] + m1x[15] * m2x[14];
|
|
||||||
mx[15] = 1.0f;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_mul(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
|
|
||||||
{
|
|
||||||
union matrix44 mf;
|
|
||||||
const float *m1x = m1->x;
|
|
||||||
const float *m2x = m2->x;
|
|
||||||
|
|
||||||
mf.x[0] = m1x[0] * m2x[0] + m1x[1] * m2x[4] + m1x[2] * m2x[8] + m1x[3] * m2x[12];
|
|
||||||
mf.x[1] = m1x[0] * m2x[1] + m1x[1] * m2x[5] + m1x[2] * m2x[9] + m1x[3] * m2x[13];
|
|
||||||
mf.x[2] = m1x[0] * m2x[2] + m1x[1] * m2x[6] + m1x[2] * m2x[10] + m1x[3] * m2x[14];
|
|
||||||
mf.x[3] = m1x[0] * m2x[3] + m1x[1] * m2x[7] + m1x[2] * m2x[11] + m1x[3] * m2x[15];
|
|
||||||
|
|
||||||
mf.x[4] = m1x[4] * m2x[0] + m1x[5] * m2x[4] + m1x[6] * m2x[8] + m1x[7] * m2x[12];
|
|
||||||
mf.x[5] = m1x[4] * m2x[1] + m1x[5] * m2x[5] + m1x[6] * m2x[9] + m1x[7] * m2x[13];
|
|
||||||
mf.x[6] = m1x[4] * m2x[2] + m1x[5] * m2x[6] + m1x[6] * m2x[10] + m1x[7] * m2x[14];
|
|
||||||
mf.x[7] = m1x[4] * m2x[3] + m1x[5] * m2x[7] + m1x[6] * m2x[11] + m1x[7] * m2x[15];
|
|
||||||
|
|
||||||
mf.x[8] = m1x[8] * m2x[0] + m1x[9] * m2x[4] + m1x[10] * m2x[8] + m1x[11] * m2x[12];
|
|
||||||
mf.x[9] = m1x[8] * m2x[1] + m1x[9] * m2x[5] + m1x[10] * m2x[9] + m1x[11] * m2x[13];
|
|
||||||
mf.x[10] = m1x[8] * m2x[2] + m1x[9] * m2x[6] + m1x[10] * m2x[10] + m1x[11] * m2x[14];
|
|
||||||
mf.x[11] = m1x[8] * m2x[3] + m1x[9] * m2x[7] + m1x[10] * m2x[11] + m1x[11] * m2x[15];
|
|
||||||
|
|
||||||
mf.x[12] = m1x[12] * m2x[0] + m1x[13] * m2x[4] + m1x[14] * m2x[8] + m1x[15] * m2x[12];
|
|
||||||
mf.x[13] = m1x[12] * m2x[1] + m1x[13] * m2x[5] + m1x[14] * m2x[9] + m1x[15] * m2x[13];
|
|
||||||
mf.x[14] = m1x[12] * m2x[2] + m1x[13] * m2x[6] + m1x[14] * m2x[10] + m1x[15] * m2x[14];
|
|
||||||
mf.x[15] = m1x[12] * m2x[3] + m1x[13] * m2x[7] + m1x[14] * m2x[11] + m1x[15] * m2x[15];
|
|
||||||
|
|
||||||
*m = mf;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_mul(struct vector3 *v, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float x = v->x * C[0][0] + v->y * C[0][1] + v->z * C[0][2] + C[0][3];
|
|
||||||
float y = v->x * C[1][0] + v->y * C[1][1] + v->z * C[1][2] + C[1][3];
|
|
||||||
float z = v->x * C[2][0] + v->y * C[2][1] + v->z * C[2][2] + C[2][3];
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector4 *
|
|
||||||
vector4_mul(struct vector4 *v, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float x = v->x * C[0][0] + v->y * C[0][1] + v->z * C[0][2] + v->w * C[0][3];
|
|
||||||
float y = v->x * C[1][0] + v->y * C[1][1] + v->z * C[1][2] + v->w * C[1][3];
|
|
||||||
float z = v->x * C[2][0] + v->y * C[2][1] + v->z * C[2][2] + v->w * C[2][3];
|
|
||||||
float w = v->x * C[3][0] + v->y * C[3][1] + v->z * C[3][2] + v->w * C[3][3];
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
v->w = w;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_mul33(struct vector3 *v, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float x = v->x * C[0][0] + v->y * C[0][1] + v->z * C[0][2];
|
|
||||||
float y = v->x * C[1][0] + v->y * C[1][1] + v->z * C[1][2];
|
|
||||||
float z = v->x * C[2][0] + v->y * C[2][1] + v->z * C[2][2];
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_transposed(union matrix44 *m)
|
|
||||||
{
|
|
||||||
int x, y;
|
|
||||||
for (y = 0; y < 4; ++y)
|
|
||||||
{
|
|
||||||
for (x = y + 1; x < 4; ++x)
|
|
||||||
{
|
|
||||||
float tmp = C[x][y];
|
|
||||||
C[x][y] = C[y][x];
|
|
||||||
C[y][x] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
matrix44_determinant(const union matrix44 *m)
|
|
||||||
{
|
|
||||||
return C[0][3] * C[1][2] * C[2][1] * C[3][0] - C[0][2] * C[1][3] * C[2][1] * C[3][0] - C[0][3] * C[1][1] * C[2][2] * C[3][0] + C[0][1] * C[1][3] * C[2][2] * C[3][0] +
|
|
||||||
C[0][2] * C[1][1] * C[2][3] * C[3][0] - C[0][1] * C[1][2] * C[2][3] * C[3][0] - C[0][3] * C[1][2] * C[2][0] * C[3][1] + C[0][2] * C[1][3] * C[2][0] * C[3][1] +
|
|
||||||
C[0][3] * C[1][0] * C[2][2] * C[3][1] - C[0][0] * C[1][3] * C[2][2] * C[3][1] - C[0][2] * C[1][0] * C[2][3] * C[3][1] + C[0][0] * C[1][2] * C[2][3] * C[3][1] +
|
|
||||||
C[0][3] * C[1][1] * C[2][0] * C[3][2] - C[0][1] * C[1][3] * C[2][0] * C[3][2] - C[0][3] * C[1][0] * C[2][1] * C[3][2] + C[0][0] * C[1][3] * C[2][1] * C[3][2] +
|
|
||||||
C[0][1] * C[1][0] * C[2][3] * C[3][2] - C[0][0] * C[1][1] * C[2][3] * C[3][2] - C[0][2] * C[1][1] * C[2][0] * C[3][3] + C[0][1] * C[1][2] * C[2][0] * C[3][3] +
|
|
||||||
C[0][2] * C[1][0] * C[2][1] * C[3][3] - C[0][0] * C[1][2] * C[2][1] * C[3][3] - C[0][1] * C[1][0] * C[2][2] * C[3][3] + C[0][0] * C[1][1] * C[2][2] * C[3][3];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_inverted(union matrix44 *dst, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float d = matrix44_determinant(m);
|
|
||||||
if (d == 0)
|
|
||||||
{
|
|
||||||
*dst = *m;
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
d = 1.0f / d;
|
|
||||||
|
|
||||||
dst->c[0][0] = d * (C[1][2] * C[2][3] * C[3][1] - C[1][3] * C[2][2] * C[3][1] + C[1][3] * C[2][1] * C[3][2] - C[1][1] * C[2][3] * C[3][2] - C[1][2] * C[2][1] * C[3][3] + C[1][1] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[0][1] = d * (C[0][3] * C[2][2] * C[3][1] - C[0][2] * C[2][3] * C[3][1] - C[0][3] * C[2][1] * C[3][2] + C[0][1] * C[2][3] * C[3][2] + C[0][2] * C[2][1] * C[3][3] - C[0][1] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[0][2] = d * (C[0][2] * C[1][3] * C[3][1] - C[0][3] * C[1][2] * C[3][1] + C[0][3] * C[1][1] * C[3][2] - C[0][1] * C[1][3] * C[3][2] - C[0][2] * C[1][1] * C[3][3] + C[0][1] * C[1][2] * C[3][3]);
|
|
||||||
dst->c[0][3] = d * (C[0][3] * C[1][2] * C[2][1] - C[0][2] * C[1][3] * C[2][1] - C[0][3] * C[1][1] * C[2][2] + C[0][1] * C[1][3] * C[2][2] + C[0][2] * C[1][1] * C[2][3] - C[0][1] * C[1][2] * C[2][3]);
|
|
||||||
dst->c[1][0] = d * (C[1][3] * C[2][2] * C[3][0] - C[1][2] * C[2][3] * C[3][0] - C[1][3] * C[2][0] * C[3][2] + C[1][0] * C[2][3] * C[3][2] + C[1][2] * C[2][0] * C[3][3] - C[1][0] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[1][1] = d * (C[0][2] * C[2][3] * C[3][0] - C[0][3] * C[2][2] * C[3][0] + C[0][3] * C[2][0] * C[3][2] - C[0][0] * C[2][3] * C[3][2] - C[0][2] * C[2][0] * C[3][3] + C[0][0] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[1][2] = d * (C[0][3] * C[1][2] * C[3][0] - C[0][2] * C[1][3] * C[3][0] - C[0][3] * C[1][0] * C[3][2] + C[0][0] * C[1][3] * C[3][2] + C[0][2] * C[1][0] * C[3][3] - C[0][0] * C[1][2] * C[3][3]);
|
|
||||||
dst->c[1][3] = d * (C[0][2] * C[1][3] * C[2][0] - C[0][3] * C[1][2] * C[2][0] + C[0][3] * C[1][0] * C[2][2] - C[0][0] * C[1][3] * C[2][2] - C[0][2] * C[1][0] * C[2][3] + C[0][0] * C[1][2] * C[2][3]);
|
|
||||||
dst->c[2][0] = d * (C[1][1] * C[2][3] * C[3][0] - C[1][3] * C[2][1] * C[3][0] + C[1][3] * C[2][0] * C[3][1] - C[1][0] * C[2][3] * C[3][1] - C[1][1] * C[2][0] * C[3][3] + C[1][0] * C[2][1] * C[3][3]);
|
|
||||||
dst->c[2][1] = d * (C[0][3] * C[2][1] * C[3][0] - C[0][1] * C[2][3] * C[3][0] - C[0][3] * C[2][0] * C[3][1] + C[0][0] * C[2][3] * C[3][1] + C[0][1] * C[2][0] * C[3][3] - C[0][0] * C[2][1] * C[3][3]);
|
|
||||||
dst->c[2][2] = d * (C[0][1] * C[1][3] * C[3][0] - C[0][3] * C[1][1] * C[3][0] + C[0][3] * C[1][0] * C[3][1] - C[0][0] * C[1][3] * C[3][1] - C[0][1] * C[1][0] * C[3][3] + C[0][0] * C[1][1] * C[3][3]);
|
|
||||||
dst->c[2][3] = d * (C[0][3] * C[1][1] * C[2][0] - C[0][1] * C[1][3] * C[2][0] - C[0][3] * C[1][0] * C[2][1] + C[0][0] * C[1][3] * C[2][1] + C[0][1] * C[1][0] * C[2][3] - C[0][0] * C[1][1] * C[2][3]);
|
|
||||||
dst->c[3][0] = d * (C[1][2] * C[2][1] * C[3][0] - C[1][1] * C[2][2] * C[3][0] - C[1][2] * C[2][0] * C[3][1] + C[1][0] * C[2][2] * C[3][1] + C[1][1] * C[2][0] * C[3][2] - C[1][0] * C[2][1] * C[3][2]);
|
|
||||||
dst->c[3][1] = d * (C[0][1] * C[2][2] * C[3][0] - C[0][2] * C[2][1] * C[3][0] + C[0][2] * C[2][0] * C[3][1] - C[0][0] * C[2][2] * C[3][1] - C[0][1] * C[2][0] * C[3][2] + C[0][0] * C[2][1] * C[3][2]);
|
|
||||||
dst->c[3][2] = d * (C[0][2] * C[1][1] * C[3][0] - C[0][1] * C[1][2] * C[3][0] - C[0][2] * C[1][0] * C[3][1] + C[0][0] * C[1][2] * C[3][1] + C[0][1] * C[1][0] * C[3][2] - C[0][0] * C[1][1] * C[3][2]);
|
|
||||||
dst->c[3][3] = d * (C[0][1] * C[1][2] * C[2][0] - C[0][2] * C[1][1] * C[2][0] + C[0][2] * C[1][0] * C[2][1] - C[0][0] * C[1][2] * C[2][1] - C[0][1] * C[1][0] * C[2][2] + C[0][0] * C[1][1] * C[2][2]);
|
|
||||||
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
matrix44_gettrans(const union matrix44 *m, struct vector3 *trans)
|
|
||||||
{
|
|
||||||
// Getting translation is trivial
|
|
||||||
trans->x = C[3][0];
|
|
||||||
trans->y = C[3][1];
|
|
||||||
trans->z = C[3][2];
|
|
||||||
|
|
||||||
return trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
matrix44_getscale(const union matrix44 *m, struct vector3 *scale)
|
|
||||||
{
|
|
||||||
// Scale is length of columns
|
|
||||||
scale->x = sqrtf(C[0][0] * C[0][0] + C[0][1] * C[0][1] + C[0][2] * C[0][2]);
|
|
||||||
scale->y = sqrtf(C[1][0] * C[1][0] + C[1][1] * C[1][1] + C[1][2] * C[1][2]);
|
|
||||||
scale->z = sqrtf(C[2][0] * C[2][0] + C[2][1] * C[2][1] + C[2][2] * C[2][2]);
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTICE: Huanzai
|
|
||||||
// this function may be need to convert from right to left handed coordinate
|
|
||||||
static inline void
|
|
||||||
matrix44_decompose(const union matrix44 *m, struct vector3 *trans, struct vector3 *rot, struct vector3 *scale)
|
|
||||||
{
|
|
||||||
matrix44_gettrans(m, trans);
|
|
||||||
matrix44_getscale(m, scale);
|
|
||||||
|
|
||||||
if (scale->x == 0 || scale->y == 0 || scale->z == 0)
|
|
||||||
{
|
|
||||||
rot->x = 0;
|
|
||||||
rot->y = 0;
|
|
||||||
rot->z = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect negative scale with determinant and flip one arbitrary axis
|
|
||||||
if (matrix44_determinant(m) < 0)
|
|
||||||
scale->x = -scale->x;
|
|
||||||
|
|
||||||
// Combined rotation matrix YXZ
|
|
||||||
//
|
|
||||||
// Cos[y]*Cos[z]+Sin[x]*Sin[y]*Sin[z] Cos[z]*Sin[x]*Sin[y]-Cos[y]*Sin[z] Cos[x]*Sin[y]
|
|
||||||
// Cos[x]*Sin[z] Cos[x]*Cos[z] -Sin[x]
|
|
||||||
// -Cos[z]*Sin[y]+Cos[y]*Sin[x]*Sin[z] Cos[y]*Cos[z]*Sin[x]+Sin[y]*Sin[z] Cos[x]*Cos[y]
|
|
||||||
|
|
||||||
rot->x = asinf(-C[2][1] / scale->z);
|
|
||||||
|
|
||||||
// Special case: Cos[x] == 0 (when Sin[x] is +/-1)
|
|
||||||
float f = fabsf(C[2][1] / scale->z);
|
|
||||||
|
|
||||||
if (f > 0.999f && f < 1.001f)
|
|
||||||
{
|
|
||||||
// Pin arbitrarily one of y or z to zero
|
|
||||||
// Mathematical equivalent of gimbal lock
|
|
||||||
rot->y = 0;
|
|
||||||
|
|
||||||
// Now: Cos[x] = 0, Sin[x] = +/-1, Cos[y] = 1, Sin[y] = 0
|
|
||||||
// => m[0][0] = Cos[z] and m[1][0] = Sin[z]
|
|
||||||
rot->z = atan2f(-C[1][0] / scale->y, C[0][0] / scale->x);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Standard case
|
|
||||||
rot->y = atan2f(C[2][0] / scale->z, C[2][2] / scale->z);
|
|
||||||
rot->z = atan2f(C[0][1] / scale->x, C[1][1] / scale->y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float *
|
|
||||||
matrix44_to33(const union matrix44 *m, float m33[9])
|
|
||||||
{
|
|
||||||
m33[0] = C[0][0];
|
|
||||||
m33[1] = C[0][1];
|
|
||||||
m33[2] = C[0][2];
|
|
||||||
m33[3] = C[1][0];
|
|
||||||
m33[4] = C[1][1];
|
|
||||||
m33[5] = C[1][2];
|
|
||||||
m33[6] = C[2][0];
|
|
||||||
m33[7] = C[2][1];
|
|
||||||
m33[8] = C[2][2];
|
|
||||||
|
|
||||||
return m33;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef C
|
|
||||||
|
|
||||||
// plane
|
|
||||||
|
|
||||||
static inline struct plane *
|
|
||||||
plane_init(struct plane *p, const struct vector3 *normal, float d)
|
|
||||||
{
|
|
||||||
p->normal = *normal;
|
|
||||||
// normalize
|
|
||||||
float invLen = 1.0f / vector3_length(normal);
|
|
||||||
p->normal.x *= invLen;
|
|
||||||
p->normal.y *= invLen;
|
|
||||||
p->normal.z *= invLen;
|
|
||||||
p->dist = d * invLen;
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct plane *
|
|
||||||
plane_init_dot3(struct plane *p, const struct vector3 *v0, const struct vector3 *v1, const struct vector3 *v2)
|
|
||||||
{
|
|
||||||
struct vector3 a, b;
|
|
||||||
vector3_vector(&a, v1, v0);
|
|
||||||
vector3_vector(&b, v2, v0);
|
|
||||||
|
|
||||||
vector3_cross(&p->normal, &a, &b);
|
|
||||||
vector3_normalize(&p->normal);
|
|
||||||
p->dist = -vector3_dot(&p->normal, v0);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
plane_dist(const struct plane *p, const struct vector3 *v)
|
|
||||||
{
|
|
||||||
float d = vector3_dot(&p->normal, v);
|
|
||||||
return d + p->dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intersection
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
intersection_raytriangle(const struct vector3 *rayOrig, const struct vector3 *rayDir,
|
|
||||||
const struct vector3 *vert0, const struct vector3 *vert1, const struct vector3 *vert2,
|
|
||||||
struct vector3 *intsPoint)
|
|
||||||
{
|
|
||||||
// Idea: Tomas Moeller and Ben Trumbore
|
|
||||||
// in Fast, Minimum Storage Ray/Triangle Intersection
|
|
||||||
|
|
||||||
// Find vectors for two edges sharing vert0
|
|
||||||
struct vector3 edge1, edge2;
|
|
||||||
vector3_vector(&edge1, vert1, vert0);
|
|
||||||
vector3_vector(&edge2, vert2, vert0);
|
|
||||||
|
|
||||||
// Begin calculating determinant - also used to calculate U parameter
|
|
||||||
struct vector3 pvec;
|
|
||||||
vector3_cross(&pvec, rayDir, &edge2);
|
|
||||||
|
|
||||||
// If determinant is near zero, ray lies in plane of triangle
|
|
||||||
float det = vector3_dot(&edge1, &pvec);
|
|
||||||
|
|
||||||
// *** Culling branch ***
|
|
||||||
/*if( det < FLT_EPSILON )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Calculate distance from vert0 to ray origin
|
|
||||||
struct vector3 tvec;
|
|
||||||
vector3_vector(&tvec, rayOrig, &vert0);
|
|
||||||
|
|
||||||
// Calculate U parameter and test bounds
|
|
||||||
float u = vector3_dot(&tvec, &pvec);
|
|
||||||
if (u < 0 || u > det )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Prepare to test V parameter
|
|
||||||
struct vector3 qvec;
|
|
||||||
vector3_cross(&qvec, &tvec, &edge1);
|
|
||||||
|
|
||||||
// Calculate V parameter and test bounds
|
|
||||||
float v = vector3_dot(rayDir, &qvec);
|
|
||||||
if (v < 0 || u + v > det )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Calculate t, scale parameters, ray intersects triangle
|
|
||||||
float t = vector3_dot(&edge2, &qvec ) / det;*/
|
|
||||||
|
|
||||||
// *** Non-culling branch ***
|
|
||||||
if (det > -FLT_EPSILON && det < FLT_EPSILON)
|
|
||||||
return 0;
|
|
||||||
float inv_det = 1.0f / det;
|
|
||||||
|
|
||||||
// Calculate distance from vert0 to ray origin
|
|
||||||
struct vector3 tvec;
|
|
||||||
vector3_vector(&tvec, rayOrig, vert0);
|
|
||||||
|
|
||||||
// Calculate U parameter and test bounds
|
|
||||||
float u = vector3_dot(&tvec, &pvec) * inv_det;
|
|
||||||
if (u < 0.0f || u > 1.0f)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Prepare to test V parameter
|
|
||||||
struct vector3 qvec;
|
|
||||||
vector3_cross(&qvec, &tvec, &edge1);
|
|
||||||
|
|
||||||
// Calculate V parameter and test bounds
|
|
||||||
float v = vector3_dot(rayDir, &qvec) * inv_det;
|
|
||||||
if (v < 0.0f || u + v > 1.0f)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Calculate t, ray intersects triangle
|
|
||||||
float t = vector3_dot(&edge2, &qvec) * inv_det;
|
|
||||||
|
|
||||||
// Calculate intersection point and test ray length and direction
|
|
||||||
intsPoint->x = rayOrig->x + rayDir->x * t;
|
|
||||||
intsPoint->y = rayOrig->y + rayDir->y * t;
|
|
||||||
intsPoint->z = rayOrig->z + rayDir->z * t;
|
|
||||||
|
|
||||||
struct vector3 vec;
|
|
||||||
vector3_vector(&vec, intsPoint, rayOrig);
|
|
||||||
if (vector3_dot(&vec, rayDir) < 0 || vector3_length(&vec) > vector3_length(rayDir))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return intsPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
minf(float a, float b)
|
|
||||||
{
|
|
||||||
return a < b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
maxf(float a, float b)
|
|
||||||
{
|
|
||||||
return a > b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
intersection_rayAABB(const struct vector3 *rayOrig, const struct vector3 *rayDir,
|
|
||||||
const struct vector3 *mins, const struct vector3 *maxs)
|
|
||||||
{
|
|
||||||
// SLAB based optimized ray/AABB intersection routine
|
|
||||||
// Idea taken from http://ompf.org/ray/
|
|
||||||
|
|
||||||
float l1 = (mins->x - rayOrig->x) / rayDir->x;
|
|
||||||
float l2 = (maxs->x - rayOrig->x) / rayDir->x;
|
|
||||||
float lmin = minf(l1, l2);
|
|
||||||
float lmax = maxf(l1, l2);
|
|
||||||
|
|
||||||
l1 = (mins->y - rayOrig->y) / rayDir->y;
|
|
||||||
l2 = (maxs->y - rayOrig->y) / rayDir->y;
|
|
||||||
lmin = maxf(minf(l1, l2), lmin);
|
|
||||||
lmax = minf(maxf(l1, l2), lmax);
|
|
||||||
|
|
||||||
l1 = (mins->z - rayOrig->z) / rayDir->z;
|
|
||||||
l2 = (maxs->z - rayOrig->z) / rayDir->z;
|
|
||||||
lmin = maxf(minf(l1, l2), lmin);
|
|
||||||
lmax = minf(maxf(l1, l2), lmax);
|
|
||||||
|
|
||||||
if ((lmax >= 0.0f) & (lmax >= lmin))
|
|
||||||
{
|
|
||||||
// Consider length
|
|
||||||
const struct vector3 rayDest = {rayOrig->x + rayDir->x, rayOrig->y + rayDir->y, rayOrig->z + rayDir->z};
|
|
||||||
const struct vector3 rayMins = {minf(rayDest.x, rayOrig->x), minf(rayDest.y, rayOrig->y), minf(rayDest.z, rayOrig->z)};
|
|
||||||
const struct vector3 rayMaxs = {maxf(rayDest.x, rayOrig->x), maxf(rayDest.y, rayOrig->y), maxf(rayDest.z, rayOrig->z)};
|
|
||||||
return (rayMins.x < maxs->x) && (rayMaxs.x > mins->x) &&
|
|
||||||
(rayMins.y < maxs->y) && (rayMaxs.y > mins->y) &&
|
|
||||||
(rayMins.z < maxs->z) && (rayMaxs.z > mins->z);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
vector3_distAABB(const struct vector3 *pos, const struct vector3 *mins, const struct vector3 *maxs)
|
|
||||||
{
|
|
||||||
struct vector3 center;
|
|
||||||
struct vector3 extent;
|
|
||||||
center.x = (mins->x + maxs->x) * 0.5f;
|
|
||||||
center.y = (mins->y + maxs->y) * 0.5f;
|
|
||||||
center.z = (mins->z + maxs->z) * 0.5f;
|
|
||||||
|
|
||||||
extent.x = (maxs->x - mins->x) * 0.5f;
|
|
||||||
extent.y = (maxs->y - mins->y) * 0.5f;
|
|
||||||
extent.z = (maxs->z - mins->z) * 0.5f;
|
|
||||||
|
|
||||||
struct vector3 nearestVec;
|
|
||||||
nearestVec.x = maxf(0, fabsf(pos->x - center.x) - extent.x);
|
|
||||||
nearestVec.y = maxf(0, fabsf(pos->y - center.y) - extent.y);
|
|
||||||
nearestVec.z = maxf(0, fabsf(pos->z - center.z) - extent.z);
|
|
||||||
|
|
||||||
return vector3_length(&nearestVec);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,835 +0,0 @@
|
|||||||
// This is a rewrite version (in C) from Horde3D (utMath.h) , http://www.horde3d.org
|
|
||||||
// Math library
|
|
||||||
//
|
|
||||||
// Coordinate system is right-handed with positive y as up axis
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ejoy3d_math_h
|
|
||||||
#define ejoy3d_math_h
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <float.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
struct vector3
|
|
||||||
{
|
|
||||||
float x, y, z;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vector4
|
|
||||||
{
|
|
||||||
float x, y, z, w;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct quaternion
|
|
||||||
{
|
|
||||||
float x, y, z, w;
|
|
||||||
};
|
|
||||||
|
|
||||||
union matrix44
|
|
||||||
{
|
|
||||||
float c[4][4];
|
|
||||||
float x[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plane
|
|
||||||
{
|
|
||||||
struct vector3 normal;
|
|
||||||
float dist;
|
|
||||||
};
|
|
||||||
|
|
||||||
// vector
|
|
||||||
|
|
||||||
static inline float *
|
|
||||||
vector3_array(struct vector3 *v)
|
|
||||||
{
|
|
||||||
return (float *)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float *
|
|
||||||
vector4_array(struct vector4 *v)
|
|
||||||
{
|
|
||||||
return (float *)v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
vector3_dot(const struct vector3 *a, const struct vector3 *b)
|
|
||||||
{
|
|
||||||
return a->x * b->x + a->y * b->y + a->z * b->z;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_cross(struct vector3 *v, const struct vector3 *a, const struct vector3 *b)
|
|
||||||
{
|
|
||||||
float x = a->y * b->z - a->z * b->y;
|
|
||||||
float y = a->z * b->x - a->x * b->z;
|
|
||||||
float z = a->x * b->y - a->y * b->x;
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_vector(struct vector3 *v, const struct vector3 *p1, const struct vector3 *p2)
|
|
||||||
{
|
|
||||||
v->x = p1->x - p2->x;
|
|
||||||
v->y = p1->y - p2->y;
|
|
||||||
v->z = p1->z - p2->z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
vector3_length(const struct vector3 *v)
|
|
||||||
{
|
|
||||||
return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_normalize(struct vector3 *v)
|
|
||||||
{
|
|
||||||
float invLen = 1.0f / vector3_length(v);
|
|
||||||
v->x *= invLen;
|
|
||||||
v->y *= invLen;
|
|
||||||
v->z *= invLen;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_to_rotation(struct vector3 *v, const struct vector3 *r)
|
|
||||||
{
|
|
||||||
// Assumes that the unrotated view vector is (0, 0, -1)
|
|
||||||
v->x = v->y = v->z = 0;
|
|
||||||
if (r->y != 0)
|
|
||||||
{
|
|
||||||
v->x = atan2f(r->y, sqrtf(r->x * r->x + r->z * r->z));
|
|
||||||
}
|
|
||||||
if (r->x != 0 || r->z != 0)
|
|
||||||
{
|
|
||||||
v->y = atan2f(-r->x, -r->z);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_lerp(struct vector3 *v, const struct vector3 *a, const struct vector3 *b, float f)
|
|
||||||
{
|
|
||||||
float x = a->x + (b->x - a->x) * f;
|
|
||||||
float y = a->y + (b->y - a->y) * f;
|
|
||||||
float z = a->z + (b->z - a->z) * f;
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// quaternion
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_mul(struct quaternion *q, const struct quaternion *a, const struct quaternion *b)
|
|
||||||
{
|
|
||||||
float x = a->y * b->z - a->z * b->y + b->x * a->w + a->x * b->w;
|
|
||||||
float y = a->z * b->x - a->x * b->z + b->y * a->w + a->y * b->w;
|
|
||||||
float z = a->x * b->y - a->y * b->x + b->z * a->w + a->z * b->w;
|
|
||||||
float w = a->w * b->w - (a->x * b->x + a->y * b->y + a->z * b->z);
|
|
||||||
|
|
||||||
q->x = x;
|
|
||||||
q->y = y;
|
|
||||||
q->z = z;
|
|
||||||
q->w = w;
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_init(struct quaternion *q, float x, float y, float z)
|
|
||||||
{
|
|
||||||
struct quaternion roll = {sinf(x * 0.5f), 0, 0, cosf(x * 0.5f)};
|
|
||||||
struct quaternion pitch = {0, sinf(y * 0.5f), 0, cosf(y * 0.5f)};
|
|
||||||
struct quaternion yaw = {0, 0, sinf(z * 0.5f), cosf(z * 0.5f)};
|
|
||||||
|
|
||||||
// Order: y * x * z
|
|
||||||
quaternion_mul(q, &pitch, &roll);
|
|
||||||
quaternion_mul(q, q, &yaw);
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_slerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
|
|
||||||
{
|
|
||||||
float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
|
|
||||||
if (cosTheta < 0)
|
|
||||||
{
|
|
||||||
cosTheta = -cosTheta;
|
|
||||||
q->x = -b->x;
|
|
||||||
q->y = -b->y;
|
|
||||||
q->z = -b->z;
|
|
||||||
q->w = -b->w;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*q = *b;
|
|
||||||
}
|
|
||||||
float scale0 = 1 - t, scale1 = t;
|
|
||||||
if ((1 - cosTheta) > 0.001f)
|
|
||||||
{
|
|
||||||
// use spherical interpolation
|
|
||||||
float theta = acosf(cosTheta);
|
|
||||||
float sinTheta = sinf(theta);
|
|
||||||
scale0 = sinf((1 - t) * theta) / sinTheta;
|
|
||||||
scale1 = sinf(t * theta) / sinTheta;
|
|
||||||
}
|
|
||||||
|
|
||||||
q->x = a->x * scale0 + q->x * scale1;
|
|
||||||
q->y = a->y * scale0 + q->y * scale1;
|
|
||||||
q->z = a->z * scale0 + q->z * scale1;
|
|
||||||
q->w = a->w * scale0 + q->w * scale1;
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_nslerp(struct quaternion *q, const struct quaternion *a, const struct quaternion *b, float t)
|
|
||||||
{
|
|
||||||
// Normalized linear quaternion interpolation
|
|
||||||
// Note: NLERP is faster than SLERP and commutative but does not yield constant velocity
|
|
||||||
|
|
||||||
float cosTheta = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
|
|
||||||
|
|
||||||
if (cosTheta < 0)
|
|
||||||
{
|
|
||||||
q->x = a->x + (-b->x - a->x) * t;
|
|
||||||
q->y = a->y + (-b->y - a->y) * t;
|
|
||||||
q->z = a->z + (-b->z - a->z) * t;
|
|
||||||
q->w = a->w + (-b->w - a->w) * t;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
q->x = a->x + (b->x - a->x) * t;
|
|
||||||
q->y = a->y + (b->y - a->y) * t;
|
|
||||||
q->z = a->z + (b->z - a->z) * t;
|
|
||||||
q->w = a->w + (b->w - a->w) * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
float invLen = 1.0f / sqrtf(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
|
|
||||||
|
|
||||||
q->x *= invLen;
|
|
||||||
q->y *= invLen;
|
|
||||||
q->z *= invLen;
|
|
||||||
q->w *= invLen;
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct quaternion *
|
|
||||||
quaternion_inverted(struct quaternion *q)
|
|
||||||
{
|
|
||||||
float len = q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
float invLen = -1.0f / len;
|
|
||||||
q->x *= invLen;
|
|
||||||
q->y *= invLen;
|
|
||||||
q->z *= invLen;
|
|
||||||
q->w *= invLen;
|
|
||||||
q->w = -q->w;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
q->x = q->y = q->z = q->w = 0;
|
|
||||||
}
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
|
|
||||||
// matrix 4*4
|
|
||||||
|
|
||||||
#define C m->c
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_identity(union matrix44 *m)
|
|
||||||
{
|
|
||||||
C[0][0] = 1;
|
|
||||||
C[1][0] = 0;
|
|
||||||
C[2][0] = 0;
|
|
||||||
C[3][0] = 0;
|
|
||||||
C[0][1] = 0;
|
|
||||||
C[1][1] = 1;
|
|
||||||
C[2][1] = 0;
|
|
||||||
C[3][1] = 0;
|
|
||||||
C[0][2] = 0;
|
|
||||||
C[1][2] = 0;
|
|
||||||
C[2][2] = 1;
|
|
||||||
C[3][2] = 0;
|
|
||||||
C[0][3] = 0;
|
|
||||||
C[1][3] = 0;
|
|
||||||
C[2][3] = 0;
|
|
||||||
C[3][3] = 1;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_from_quaternion(union matrix44 *m, const struct quaternion *q)
|
|
||||||
{
|
|
||||||
// Calculate coefficients
|
|
||||||
float x2 = q->x + q->x, y2 = q->y + q->y, z2 = q->z + q->z;
|
|
||||||
float xx = q->x * x2, xy = q->x * y2, xz = q->x * z2;
|
|
||||||
float yy = q->y * y2, yz = q->y * z2, zz = q->z * z2;
|
|
||||||
float wx = q->w * x2, wy = q->w * y2, wz = q->w * z2;
|
|
||||||
|
|
||||||
C[0][0] = 1 - (yy + zz);
|
|
||||||
C[1][0] = xy - wz;
|
|
||||||
C[2][0] = xz + wy;
|
|
||||||
C[3][0] = 0;
|
|
||||||
C[0][1] = xy + wz;
|
|
||||||
C[1][1] = 1 - (xx + zz);
|
|
||||||
C[2][1] = yz - wx;
|
|
||||||
C[3][1] = 0;
|
|
||||||
C[0][2] = xz - wy;
|
|
||||||
C[1][2] = yz + wx;
|
|
||||||
C[2][2] = 1 - (xx + yy);
|
|
||||||
C[3][2] = 0;
|
|
||||||
C[0][3] = 0;
|
|
||||||
C[1][3] = 0;
|
|
||||||
C[2][3] = 0;
|
|
||||||
C[3][3] = 1;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_trans(union matrix44 *m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
C[3][0] = x;
|
|
||||||
C[3][1] = y;
|
|
||||||
C[3][2] = z;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_scale(union matrix44 *m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
C[0][0] = x;
|
|
||||||
C[1][1] = y;
|
|
||||||
C[2][2] = z;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_rot(union matrix44 *m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
// Rotation order: YXZ [* Vector]
|
|
||||||
struct quaternion q;
|
|
||||||
quaternion_init(&q, x, y, z);
|
|
||||||
|
|
||||||
return matrix44_from_quaternion(m, &q);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_rot_axis(union matrix44 *m, const struct vector3 *axis, float angle)
|
|
||||||
{
|
|
||||||
float t = sinf(angle * 0.5f);
|
|
||||||
float x = axis->x * t;
|
|
||||||
float y = axis->y * t;
|
|
||||||
float z = axis->z * t;
|
|
||||||
struct quaternion q = {x, y, z, cosf(angle * 0.5f)};
|
|
||||||
|
|
||||||
return matrix44_from_quaternion(m, &q);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_perspective(union matrix44 *m, float l, float r, float b, float t, float n, float f)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
float *mx = m->x;
|
|
||||||
|
|
||||||
mx[0] = 2 * n / (r - l);
|
|
||||||
mx[5] = 2 * n / (t - b);
|
|
||||||
mx[8] = (r + l) / (r - l);
|
|
||||||
mx[9] = (t + b) / (t - b);
|
|
||||||
mx[10] = -(f + n) / (f - n);
|
|
||||||
mx[11] = -1;
|
|
||||||
mx[14] = -2 * f * n / (f - n);
|
|
||||||
mx[15] = 0;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_ortho(union matrix44 *m, float l, float r, float b, float t, float n, float f)
|
|
||||||
{
|
|
||||||
matrix44_identity(m);
|
|
||||||
float *mx = m->x;
|
|
||||||
|
|
||||||
mx[0] = 2 / (r - l);
|
|
||||||
mx[5] = 2 / (t - b);
|
|
||||||
mx[10] = -2 / (f - n);
|
|
||||||
mx[12] = -(r + l) / (r - l);
|
|
||||||
mx[13] = -(t + b) / (t - b);
|
|
||||||
mx[14] = -(f + n) / (f - n);
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_fastmul43(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
|
|
||||||
{
|
|
||||||
// Note: m may not be the same as m1 or m2
|
|
||||||
|
|
||||||
const float *m1x = m1->x;
|
|
||||||
const float *m2x = m2->x;
|
|
||||||
float *mx = m->x;
|
|
||||||
|
|
||||||
mx[0] = m1x[0] * m2x[0] + m1x[4] * m2x[1] + m1x[8] * m2x[2];
|
|
||||||
mx[1] = m1x[1] * m2x[0] + m1x[5] * m2x[1] + m1x[9] * m2x[2];
|
|
||||||
mx[2] = m1x[2] * m2x[0] + m1x[6] * m2x[1] + m1x[10] * m2x[2];
|
|
||||||
mx[3] = 0.0f;
|
|
||||||
|
|
||||||
mx[4] = m1x[0] * m2x[4] + m1x[4] * m2x[5] + m1x[8] * m2x[6];
|
|
||||||
mx[5] = m1x[1] * m2x[4] + m1x[5] * m2x[5] + m1x[9] * m2x[6];
|
|
||||||
mx[6] = m1x[2] * m2x[4] + m1x[6] * m2x[5] + m1x[10] * m2x[6];
|
|
||||||
mx[7] = 0.0f;
|
|
||||||
|
|
||||||
mx[8] = m1x[0] * m2x[8] + m1x[4] * m2x[9] + m1x[8] * m2x[10];
|
|
||||||
mx[9] = m1x[1] * m2x[8] + m1x[5] * m2x[9] + m1x[9] * m2x[10];
|
|
||||||
mx[10] = m1x[2] * m2x[8] + m1x[6] * m2x[9] + m1x[10] * m2x[10];
|
|
||||||
mx[11] = 0.0f;
|
|
||||||
|
|
||||||
mx[12] = m1x[0] * m2x[12] + m1x[4] * m2x[13] + m1x[8] * m2x[14] + m1x[12] * m2x[15];
|
|
||||||
mx[13] = m1x[1] * m2x[12] + m1x[5] * m2x[13] + m1x[9] * m2x[14] + m1x[13] * m2x[15];
|
|
||||||
mx[14] = m1x[2] * m2x[12] + m1x[6] * m2x[13] + m1x[10] * m2x[14] + m1x[14] * m2x[15];
|
|
||||||
mx[15] = 1.0f;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_mul(union matrix44 *m, const union matrix44 *m1, const union matrix44 *m2)
|
|
||||||
{
|
|
||||||
union matrix44 mf;
|
|
||||||
const float *m1x = m1->x;
|
|
||||||
const float *m2x = m2->x;
|
|
||||||
|
|
||||||
mf.x[0] = m1x[0] * m2x[0] + m1x[4] * m2x[1] + m1x[8] * m2x[2] + m1x[12] * m2x[3];
|
|
||||||
mf.x[1] = m1x[1] * m2x[0] + m1x[5] * m2x[1] + m1x[9] * m2x[2] + m1x[13] * m2x[3];
|
|
||||||
mf.x[2] = m1x[2] * m2x[0] + m1x[6] * m2x[1] + m1x[10] * m2x[2] + m1x[14] * m2x[3];
|
|
||||||
mf.x[3] = m1x[3] * m2x[0] + m1x[7] * m2x[1] + m1x[11] * m2x[2] + m1x[15] * m2x[3];
|
|
||||||
|
|
||||||
mf.x[4] = m1x[0] * m2x[4] + m1x[4] * m2x[5] + m1x[8] * m2x[6] + m1x[12] * m2x[7];
|
|
||||||
mf.x[5] = m1x[1] * m2x[4] + m1x[5] * m2x[5] + m1x[9] * m2x[6] + m1x[13] * m2x[7];
|
|
||||||
mf.x[6] = m1x[2] * m2x[4] + m1x[6] * m2x[5] + m1x[10] * m2x[6] + m1x[14] * m2x[7];
|
|
||||||
mf.x[7] = m1x[3] * m2x[4] + m1x[7] * m2x[5] + m1x[11] * m2x[6] + m1x[15] * m2x[7];
|
|
||||||
|
|
||||||
mf.x[8] = m1x[0] * m2x[8] + m1x[4] * m2x[9] + m1x[8] * m2x[10] + m1x[12] * m2x[11];
|
|
||||||
mf.x[9] = m1x[1] * m2x[8] + m1x[5] * m2x[9] + m1x[9] * m2x[10] + m1x[13] * m2x[11];
|
|
||||||
mf.x[10] = m1x[2] * m2x[8] + m1x[6] * m2x[9] + m1x[10] * m2x[10] + m1x[14] * m2x[11];
|
|
||||||
mf.x[11] = m1x[3] * m2x[8] + m1x[7] * m2x[9] + m1x[11] * m2x[10] + m1x[15] * m2x[11];
|
|
||||||
|
|
||||||
mf.x[12] = m1x[0] * m2x[12] + m1x[4] * m2x[13] + m1x[8] * m2x[14] + m1x[12] * m2x[15];
|
|
||||||
mf.x[13] = m1x[1] * m2x[12] + m1x[5] * m2x[13] + m1x[9] * m2x[14] + m1x[13] * m2x[15];
|
|
||||||
mf.x[14] = m1x[2] * m2x[12] + m1x[6] * m2x[13] + m1x[10] * m2x[14] + m1x[14] * m2x[15];
|
|
||||||
mf.x[15] = m1x[3] * m2x[12] + m1x[7] * m2x[13] + m1x[11] * m2x[14] + m1x[15] * m2x[15];
|
|
||||||
|
|
||||||
*m = mf;
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
// vector * matrix
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_mul(struct vector3 *v, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float x = v->x * C[0][0] + v->y * C[1][0] + v->z * C[2][0] + C[3][0];
|
|
||||||
float y = v->x * C[0][1] + v->y * C[1][1] + v->z * C[2][1] + C[3][1];
|
|
||||||
float z = v->x * C[0][2] + v->y * C[1][2] + v->z * C[2][2] + C[3][2];
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector4 *
|
|
||||||
vector4_mul(struct vector4 *v, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float x = v->x * C[0][0] + v->y * C[1][0] + v->z * C[2][0] + v->w * C[3][0];
|
|
||||||
float y = v->x * C[0][1] + v->y * C[1][1] + v->z * C[2][1] + v->w * C[3][1];
|
|
||||||
float z = v->x * C[0][2] + v->y * C[1][2] + v->z * C[2][2] + v->w * C[3][2];
|
|
||||||
float w = v->x * C[0][3] + v->y * C[1][3] + v->z * C[2][3] + v->w * C[3][3];
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
v->w = w;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
vector3_mul33(struct vector3 *v, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float x = v->x * C[0][0] + v->y * C[1][0] + v->z * C[2][0];
|
|
||||||
float y = v->x * C[0][1] + v->y * C[1][1] + v->z * C[2][1];
|
|
||||||
float z = v->x * C[0][2] + v->y * C[1][2] + v->z * C[2][2];
|
|
||||||
|
|
||||||
v->x = x;
|
|
||||||
v->y = y;
|
|
||||||
v->z = z;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_transposed(union matrix44 *m)
|
|
||||||
{
|
|
||||||
int x, y;
|
|
||||||
for (y = 0; y < 4; ++y)
|
|
||||||
{
|
|
||||||
for (x = y + 1; x < 4; ++x)
|
|
||||||
{
|
|
||||||
float tmp = C[x][y];
|
|
||||||
C[x][y] = C[y][x];
|
|
||||||
C[y][x] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
matrix44_determinant(const union matrix44 *m)
|
|
||||||
{
|
|
||||||
return C[0][3] * C[1][2] * C[2][1] * C[3][0] - C[0][2] * C[1][3] * C[2][1] * C[3][0] - C[0][3] * C[1][1] * C[2][2] * C[3][0] + C[0][1] * C[1][3] * C[2][2] * C[3][0] +
|
|
||||||
C[0][2] * C[1][1] * C[2][3] * C[3][0] - C[0][1] * C[1][2] * C[2][3] * C[3][0] - C[0][3] * C[1][2] * C[2][0] * C[3][1] + C[0][2] * C[1][3] * C[2][0] * C[3][1] +
|
|
||||||
C[0][3] * C[1][0] * C[2][2] * C[3][1] - C[0][0] * C[1][3] * C[2][2] * C[3][1] - C[0][2] * C[1][0] * C[2][3] * C[3][1] + C[0][0] * C[1][2] * C[2][3] * C[3][1] +
|
|
||||||
C[0][3] * C[1][1] * C[2][0] * C[3][2] - C[0][1] * C[1][3] * C[2][0] * C[3][2] - C[0][3] * C[1][0] * C[2][1] * C[3][2] + C[0][0] * C[1][3] * C[2][1] * C[3][2] +
|
|
||||||
C[0][1] * C[1][0] * C[2][3] * C[3][2] - C[0][0] * C[1][1] * C[2][3] * C[3][2] - C[0][2] * C[1][1] * C[2][0] * C[3][3] + C[0][1] * C[1][2] * C[2][0] * C[3][3] +
|
|
||||||
C[0][2] * C[1][0] * C[2][1] * C[3][3] - C[0][0] * C[1][2] * C[2][1] * C[3][3] - C[0][1] * C[1][0] * C[2][2] * C[3][3] + C[0][0] * C[1][1] * C[2][2] * C[3][3];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline union matrix44 *
|
|
||||||
matrix44_inverted(union matrix44 *dst, const union matrix44 *m)
|
|
||||||
{
|
|
||||||
float d = matrix44_determinant(m);
|
|
||||||
if (d == 0)
|
|
||||||
{
|
|
||||||
*dst = *m;
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
d = 1.0f / d;
|
|
||||||
|
|
||||||
dst->c[0][0] = d * (C[1][2] * C[2][3] * C[3][1] - C[1][3] * C[2][2] * C[3][1] + C[1][3] * C[2][1] * C[3][2] - C[1][1] * C[2][3] * C[3][2] - C[1][2] * C[2][1] * C[3][3] + C[1][1] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[0][1] = d * (C[0][3] * C[2][2] * C[3][1] - C[0][2] * C[2][3] * C[3][1] - C[0][3] * C[2][1] * C[3][2] + C[0][1] * C[2][3] * C[3][2] + C[0][2] * C[2][1] * C[3][3] - C[0][1] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[0][2] = d * (C[0][2] * C[1][3] * C[3][1] - C[0][3] * C[1][2] * C[3][1] + C[0][3] * C[1][1] * C[3][2] - C[0][1] * C[1][3] * C[3][2] - C[0][2] * C[1][1] * C[3][3] + C[0][1] * C[1][2] * C[3][3]);
|
|
||||||
dst->c[0][3] = d * (C[0][3] * C[1][2] * C[2][1] - C[0][2] * C[1][3] * C[2][1] - C[0][3] * C[1][1] * C[2][2] + C[0][1] * C[1][3] * C[2][2] + C[0][2] * C[1][1] * C[2][3] - C[0][1] * C[1][2] * C[2][3]);
|
|
||||||
dst->c[1][0] = d * (C[1][3] * C[2][2] * C[3][0] - C[1][2] * C[2][3] * C[3][0] - C[1][3] * C[2][0] * C[3][2] + C[1][0] * C[2][3] * C[3][2] + C[1][2] * C[2][0] * C[3][3] - C[1][0] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[1][1] = d * (C[0][2] * C[2][3] * C[3][0] - C[0][3] * C[2][2] * C[3][0] + C[0][3] * C[2][0] * C[3][2] - C[0][0] * C[2][3] * C[3][2] - C[0][2] * C[2][0] * C[3][3] + C[0][0] * C[2][2] * C[3][3]);
|
|
||||||
dst->c[1][2] = d * (C[0][3] * C[1][2] * C[3][0] - C[0][2] * C[1][3] * C[3][0] - C[0][3] * C[1][0] * C[3][2] + C[0][0] * C[1][3] * C[3][2] + C[0][2] * C[1][0] * C[3][3] - C[0][0] * C[1][2] * C[3][3]);
|
|
||||||
dst->c[1][3] = d * (C[0][2] * C[1][3] * C[2][0] - C[0][3] * C[1][2] * C[2][0] + C[0][3] * C[1][0] * C[2][2] - C[0][0] * C[1][3] * C[2][2] - C[0][2] * C[1][0] * C[2][3] + C[0][0] * C[1][2] * C[2][3]);
|
|
||||||
dst->c[2][0] = d * (C[1][1] * C[2][3] * C[3][0] - C[1][3] * C[2][1] * C[3][0] + C[1][3] * C[2][0] * C[3][1] - C[1][0] * C[2][3] * C[3][1] - C[1][1] * C[2][0] * C[3][3] + C[1][0] * C[2][1] * C[3][3]);
|
|
||||||
dst->c[2][1] = d * (C[0][3] * C[2][1] * C[3][0] - C[0][1] * C[2][3] * C[3][0] - C[0][3] * C[2][0] * C[3][1] + C[0][0] * C[2][3] * C[3][1] + C[0][1] * C[2][0] * C[3][3] - C[0][0] * C[2][1] * C[3][3]);
|
|
||||||
dst->c[2][2] = d * (C[0][1] * C[1][3] * C[3][0] - C[0][3] * C[1][1] * C[3][0] + C[0][3] * C[1][0] * C[3][1] - C[0][0] * C[1][3] * C[3][1] - C[0][1] * C[1][0] * C[3][3] + C[0][0] * C[1][1] * C[3][3]);
|
|
||||||
dst->c[2][3] = d * (C[0][3] * C[1][1] * C[2][0] - C[0][1] * C[1][3] * C[2][0] - C[0][3] * C[1][0] * C[2][1] + C[0][0] * C[1][3] * C[2][1] + C[0][1] * C[1][0] * C[2][3] - C[0][0] * C[1][1] * C[2][3]);
|
|
||||||
dst->c[3][0] = d * (C[1][2] * C[2][1] * C[3][0] - C[1][1] * C[2][2] * C[3][0] - C[1][2] * C[2][0] * C[3][1] + C[1][0] * C[2][2] * C[3][1] + C[1][1] * C[2][0] * C[3][2] - C[1][0] * C[2][1] * C[3][2]);
|
|
||||||
dst->c[3][1] = d * (C[0][1] * C[2][2] * C[3][0] - C[0][2] * C[2][1] * C[3][0] + C[0][2] * C[2][0] * C[3][1] - C[0][0] * C[2][2] * C[3][1] - C[0][1] * C[2][0] * C[3][2] + C[0][0] * C[2][1] * C[3][2]);
|
|
||||||
dst->c[3][2] = d * (C[0][2] * C[1][1] * C[3][0] - C[0][1] * C[1][2] * C[3][0] - C[0][2] * C[1][0] * C[3][1] + C[0][0] * C[1][2] * C[3][1] + C[0][1] * C[1][0] * C[3][2] - C[0][0] * C[1][1] * C[3][2]);
|
|
||||||
dst->c[3][3] = d * (C[0][1] * C[1][2] * C[2][0] - C[0][2] * C[1][1] * C[2][0] + C[0][2] * C[1][0] * C[2][1] - C[0][0] * C[1][2] * C[2][1] - C[0][1] * C[1][0] * C[2][2] + C[0][0] * C[1][1] * C[2][2]);
|
|
||||||
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
matrix44_gettrans(const union matrix44 *m, struct vector3 *trans)
|
|
||||||
{
|
|
||||||
// Getting translation is trivial
|
|
||||||
trans->x = C[3][0];
|
|
||||||
trans->y = C[3][1];
|
|
||||||
trans->z = C[3][2];
|
|
||||||
|
|
||||||
return trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
matrix44_getscale(const union matrix44 *m, struct vector3 *scale)
|
|
||||||
{
|
|
||||||
// Scale is length of columns
|
|
||||||
scale->x = sqrtf(C[0][0] * C[0][0] + C[0][1] * C[0][1] + C[0][2] * C[0][2]);
|
|
||||||
scale->y = sqrtf(C[1][0] * C[1][0] + C[1][1] * C[1][1] + C[1][2] * C[1][2]);
|
|
||||||
scale->z = sqrtf(C[2][0] * C[2][0] + C[2][1] * C[2][1] + C[2][2] * C[2][2]);
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
matrix44_decompose(const union matrix44 *m, struct vector3 *trans, struct vector3 *rot, struct vector3 *scale)
|
|
||||||
{
|
|
||||||
matrix44_gettrans(m, trans);
|
|
||||||
matrix44_getscale(m, scale);
|
|
||||||
|
|
||||||
if (scale->x == 0 || scale->y == 0 || scale->z == 0)
|
|
||||||
{
|
|
||||||
rot->x = 0;
|
|
||||||
rot->y = 0;
|
|
||||||
rot->z = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect negative scale with determinant and flip one arbitrary axis
|
|
||||||
if (matrix44_determinant(m) < 0)
|
|
||||||
scale->x = -scale->x;
|
|
||||||
|
|
||||||
// Combined rotation matrix YXZ
|
|
||||||
//
|
|
||||||
// Cos[y]*Cos[z]+Sin[x]*Sin[y]*Sin[z] Cos[z]*Sin[x]*Sin[y]-Cos[y]*Sin[z] Cos[x]*Sin[y]
|
|
||||||
// Cos[x]*Sin[z] Cos[x]*Cos[z] -Sin[x]
|
|
||||||
// -Cos[z]*Sin[y]+Cos[y]*Sin[x]*Sin[z] Cos[y]*Cos[z]*Sin[x]+Sin[y]*Sin[z] Cos[x]*Cos[y]
|
|
||||||
|
|
||||||
rot->x = asinf(-C[2][1] / scale->z);
|
|
||||||
|
|
||||||
// Special case: Cos[x] == 0 (when Sin[x] is +/-1)
|
|
||||||
float f = fabsf(C[2][1] / scale->z);
|
|
||||||
|
|
||||||
if (f > 0.999f && f < 1.001f)
|
|
||||||
{
|
|
||||||
// Pin arbitrarily one of y or z to zero
|
|
||||||
// Mathematical equivalent of gimbal lock
|
|
||||||
rot->y = 0;
|
|
||||||
|
|
||||||
// Now: Cos[x] = 0, Sin[x] = +/-1, Cos[y] = 1, Sin[y] = 0
|
|
||||||
// => m[0][0] = Cos[z] and m[1][0] = Sin[z]
|
|
||||||
rot->z = atan2f(-C[1][0] / scale->y, C[0][0] / scale->x);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Standard case
|
|
||||||
rot->y = atan2f(C[2][0] / scale->z, C[2][2] / scale->z);
|
|
||||||
rot->z = atan2f(C[0][1] / scale->x, C[1][1] / scale->y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float *
|
|
||||||
matrix44_to33(const union matrix44 *m, float m33[9])
|
|
||||||
{
|
|
||||||
m33[0] = C[0][0];
|
|
||||||
m33[1] = C[0][1];
|
|
||||||
m33[2] = C[0][2];
|
|
||||||
m33[3] = C[1][0];
|
|
||||||
m33[4] = C[1][1];
|
|
||||||
m33[5] = C[1][2];
|
|
||||||
m33[6] = C[2][0];
|
|
||||||
m33[7] = C[2][1];
|
|
||||||
m33[8] = C[2][2];
|
|
||||||
|
|
||||||
return m33;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef C
|
|
||||||
|
|
||||||
// plane
|
|
||||||
|
|
||||||
static inline struct plane *
|
|
||||||
plane_init(struct plane *p, const struct vector3 *normal, float d)
|
|
||||||
{
|
|
||||||
p->normal = *normal;
|
|
||||||
// normalize
|
|
||||||
float invLen = 1.0f / vector3_length(normal);
|
|
||||||
p->normal.x *= invLen;
|
|
||||||
p->normal.y *= invLen;
|
|
||||||
p->normal.z *= invLen;
|
|
||||||
p->dist = d * invLen;
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct plane *
|
|
||||||
plane_init_dot3(struct plane *p, const struct vector3 *v0, const struct vector3 *v1, const struct vector3 *v2)
|
|
||||||
{
|
|
||||||
struct vector3 a, b;
|
|
||||||
vector3_vector(&a, v1, v0);
|
|
||||||
vector3_vector(&b, v2, v0);
|
|
||||||
|
|
||||||
vector3_cross(&p->normal, &a, &b);
|
|
||||||
vector3_normalize(&p->normal);
|
|
||||||
p->dist = -vector3_dot(&p->normal, v0);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
plane_dist(const struct plane *p, const struct vector3 *v)
|
|
||||||
{
|
|
||||||
float d = vector3_dot(&p->normal, v);
|
|
||||||
return d + p->dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intersection
|
|
||||||
|
|
||||||
static inline struct vector3 *
|
|
||||||
intersection_raytriangle(const struct vector3 *rayOrig, const struct vector3 *rayDir,
|
|
||||||
const struct vector3 *vert0, const struct vector3 *vert1, const struct vector3 *vert2,
|
|
||||||
struct vector3 *intsPoint)
|
|
||||||
{
|
|
||||||
// Idea: Tomas Moeller and Ben Trumbore
|
|
||||||
// in Fast, Minimum Storage Ray/Triangle Intersection
|
|
||||||
|
|
||||||
// Find vectors for two edges sharing vert0
|
|
||||||
struct vector3 edge1, edge2;
|
|
||||||
vector3_vector(&edge1, vert1, vert0);
|
|
||||||
vector3_vector(&edge2, vert2, vert0);
|
|
||||||
|
|
||||||
// Begin calculating determinant - also used to calculate U parameter
|
|
||||||
struct vector3 pvec;
|
|
||||||
vector3_cross(&pvec, rayDir, &edge2);
|
|
||||||
|
|
||||||
// If determinant is near zero, ray lies in plane of triangle
|
|
||||||
float det = vector3_dot(&edge1, &pvec);
|
|
||||||
|
|
||||||
// *** Culling branch ***
|
|
||||||
/*if( det < FLT_EPSILON )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Calculate distance from vert0 to ray origin
|
|
||||||
struct vector3 tvec;
|
|
||||||
vector3_vector(&tvec, rayOrig, &vert0);
|
|
||||||
|
|
||||||
// Calculate U parameter and test bounds
|
|
||||||
float u = vector3_dot(&tvec, &pvec);
|
|
||||||
if (u < 0 || u > det )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Prepare to test V parameter
|
|
||||||
struct vector3 qvec;
|
|
||||||
vector3_cross(&qvec, &tvec, &edge1);
|
|
||||||
|
|
||||||
// Calculate V parameter and test bounds
|
|
||||||
float v = vector3_dot(rayDir, &qvec);
|
|
||||||
if (v < 0 || u + v > det )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Calculate t, scale parameters, ray intersects triangle
|
|
||||||
float t = vector3_dot(&edge2, &qvec ) / det;*/
|
|
||||||
|
|
||||||
// *** Non-culling branch ***
|
|
||||||
if (det > -FLT_EPSILON && det < FLT_EPSILON)
|
|
||||||
return 0;
|
|
||||||
float inv_det = 1.0f / det;
|
|
||||||
|
|
||||||
// Calculate distance from vert0 to ray origin
|
|
||||||
struct vector3 tvec;
|
|
||||||
vector3_vector(&tvec, rayOrig, vert0);
|
|
||||||
|
|
||||||
// Calculate U parameter and test bounds
|
|
||||||
float u = vector3_dot(&tvec, &pvec) * inv_det;
|
|
||||||
if (u < 0.0f || u > 1.0f)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Prepare to test V parameter
|
|
||||||
struct vector3 qvec;
|
|
||||||
vector3_cross(&qvec, &tvec, &edge1);
|
|
||||||
|
|
||||||
// Calculate V parameter and test bounds
|
|
||||||
float v = vector3_dot(rayDir, &qvec) * inv_det;
|
|
||||||
if (v < 0.0f || u + v > 1.0f)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Calculate t, ray intersects triangle
|
|
||||||
float t = vector3_dot(&edge2, &qvec) * inv_det;
|
|
||||||
|
|
||||||
// Calculate intersection point and test ray length and direction
|
|
||||||
intsPoint->x = rayOrig->x + rayDir->x * t;
|
|
||||||
intsPoint->y = rayOrig->y + rayDir->y * t;
|
|
||||||
intsPoint->z = rayOrig->z + rayDir->z * t;
|
|
||||||
|
|
||||||
struct vector3 vec;
|
|
||||||
vector3_vector(&vec, intsPoint, rayOrig);
|
|
||||||
if (vector3_dot(&vec, rayDir) < 0 || vector3_length(&vec) > vector3_length(rayDir))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return intsPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
minf(float a, float b)
|
|
||||||
{
|
|
||||||
return a < b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
maxf(float a, float b)
|
|
||||||
{
|
|
||||||
return a > b ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
intersection_rayAABB(const struct vector3 *rayOrig, const struct vector3 *rayDir,
|
|
||||||
const struct vector3 *mins, const struct vector3 *maxs)
|
|
||||||
{
|
|
||||||
// SLAB based optimized ray/AABB intersection routine
|
|
||||||
// Idea taken from http://ompf.org/ray/
|
|
||||||
|
|
||||||
float l1 = (mins->x - rayOrig->x) / rayDir->x;
|
|
||||||
float l2 = (maxs->x - rayOrig->x) / rayDir->x;
|
|
||||||
float lmin = minf(l1, l2);
|
|
||||||
float lmax = maxf(l1, l2);
|
|
||||||
|
|
||||||
l1 = (mins->y - rayOrig->y) / rayDir->y;
|
|
||||||
l2 = (maxs->y - rayOrig->y) / rayDir->y;
|
|
||||||
lmin = maxf(minf(l1, l2), lmin);
|
|
||||||
lmax = minf(maxf(l1, l2), lmax);
|
|
||||||
|
|
||||||
l1 = (mins->z - rayOrig->z) / rayDir->z;
|
|
||||||
l2 = (maxs->z - rayOrig->z) / rayDir->z;
|
|
||||||
lmin = maxf(minf(l1, l2), lmin);
|
|
||||||
lmax = minf(maxf(l1, l2), lmax);
|
|
||||||
|
|
||||||
if ((lmax >= 0.0f) & (lmax >= lmin))
|
|
||||||
{
|
|
||||||
// Consider length
|
|
||||||
const struct vector3 rayDest = {rayOrig->x + rayDir->x, rayOrig->y + rayDir->y, rayOrig->z + rayDir->z};
|
|
||||||
const struct vector3 rayMins = {minf(rayDest.x, rayOrig->x), minf(rayDest.y, rayOrig->y), minf(rayDest.z, rayOrig->z)};
|
|
||||||
const struct vector3 rayMaxs = {maxf(rayDest.x, rayOrig->x), maxf(rayDest.y, rayOrig->y), maxf(rayDest.z, rayOrig->z)};
|
|
||||||
return (rayMins.x < maxs->x) && (rayMaxs.x > mins->x) &&
|
|
||||||
(rayMins.y < maxs->y) && (rayMaxs.y > mins->y) &&
|
|
||||||
(rayMins.z < maxs->z) && (rayMaxs.z > mins->z);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline float
|
|
||||||
vector3_distAABB(const struct vector3 *pos, const struct vector3 *mins, const struct vector3 *maxs)
|
|
||||||
{
|
|
||||||
struct vector3 center;
|
|
||||||
struct vector3 extent;
|
|
||||||
center.x = (mins->x + maxs->x) * 0.5f;
|
|
||||||
center.y = (mins->y + maxs->y) * 0.5f;
|
|
||||||
center.z = (mins->z + maxs->z) * 0.5f;
|
|
||||||
|
|
||||||
extent.x = (maxs->x - mins->x) * 0.5f;
|
|
||||||
extent.y = (maxs->y - mins->y) * 0.5f;
|
|
||||||
extent.z = (maxs->z - mins->z) * 0.5f;
|
|
||||||
|
|
||||||
struct vector3 nearestVec;
|
|
||||||
nearestVec.x = maxf(0, fabsf(pos->x - center.x) - extent.x);
|
|
||||||
nearestVec.y = maxf(0, fabsf(pos->y - center.y) - extent.y);
|
|
||||||
nearestVec.z = maxf(0, fabsf(pos->z - center.z) - extent.z);
|
|
||||||
|
|
||||||
return vector3_length(&nearestVec);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
o
|
||||||
|
*.dll
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
SKYNET_ROOT ?= ../../skynet
|
||||||
|
include $(SKYNET_ROOT)/platform.mk
|
||||||
|
|
||||||
|
LUALIB ?= $(SKYNET_ROOT)/3rd/lua/
|
||||||
|
LUAINC ?= $(SKYNET_ROOT)/3rd/lua/
|
||||||
|
GLM_INC = -I ../../3rd/glm
|
||||||
|
ODIR = o
|
||||||
|
OUTPUT= ../../luaclib/
|
||||||
|
|
||||||
|
PLAT ?= none
|
||||||
|
ifeq ($(PLAT), macosx)
|
||||||
|
CFLAGS = -g -O2 -dynamiclib -Wl,-undefined,dynamic_lookup -std=gnu99
|
||||||
|
else
|
||||||
|
ifeq ($(PLAT), linux)
|
||||||
|
CFLAGS = -g -O2 -shared -fPIC -std=gnu99
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
all : $(OUTPUT)math3d.so
|
||||||
|
|
||||||
|
$(ODIR)/linalg.o : linalg.c | $(ODIR)
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
|
||||||
|
|
||||||
|
$(ODIR)/math3d.o : math3d.c | $(ODIR)
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
|
||||||
|
|
||||||
|
$(ODIR)/mathfunc.o : mathfunc.cpp | $(ODIR)
|
||||||
|
$(CXX) -c $(CFLAGS) -Wno-char-subscripts -o $@ $^ $(GLM_INC)
|
||||||
|
|
||||||
|
$(ODIR)/mathadapter.o : mathadapter.c | $(ODIR)
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
|
||||||
|
|
||||||
|
$(ODIR)/testadapter.o : testadapter.c | $(ODIR)
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $^ $(LUAINC)
|
||||||
|
|
||||||
|
$(OUTPUT)math3d.so : $(ODIR)/linalg.o $(ODIR)/math3d.o $(ODIR)/mathfunc.o $(ODIR)/mathadapter.o $(ODIR)/testadapter.o
|
||||||
|
$(CXX) --shared $(CFLAGS) -o $@ $^ -lstdc++ $(LUALIB)
|
||||||
|
|
||||||
|
$(ODIR) :
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
clean :
|
||||||
|
rm -rf $(ODIR) *.so
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef math_fastcall_h
|
||||||
|
#define math_fastcall_h
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include "linalg.h"
|
||||||
|
#include "refstack.h"
|
||||||
|
|
||||||
|
typedef int (*MFunction)(lua_State *L, struct lastack *LS, struct ref_stack *RS);
|
||||||
|
|
||||||
|
#define FASTMATH(f)\
|
||||||
|
int m_##f(lua_State *L, struct lastack *LS_, struct ref_stack *RS_) {\
|
||||||
|
struct ref_stack tmpRS; \
|
||||||
|
struct lastack *LS;\
|
||||||
|
struct ref_stack *RS;\
|
||||||
|
if (L == NULL) {\
|
||||||
|
L = RS_->L; LS=LS_; RS=RS_; (void)LS; (void)RS;\
|
||||||
|
} else {\
|
||||||
|
LS = getLS(L, 1); refstack_init(&tmpRS, L); RS = &tmpRS;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MFUNCTION(f) #f, (lua_CFunction)( m_##f )
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,808 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "linalg.h"
|
||||||
|
|
||||||
|
#define MINCAP 128
|
||||||
|
|
||||||
|
#define VECTOR4 4
|
||||||
|
#define MATRIX 16
|
||||||
|
|
||||||
|
// Constant: version should be 0, id is the constant id, persistent should be 1
|
||||||
|
|
||||||
|
static float c_ident_vec[4] = { 0,0,0,1 };
|
||||||
|
static float c_ident_mat[16] = {
|
||||||
|
1,0,0,0,
|
||||||
|
0,1,0,0,
|
||||||
|
0,0,1,0,
|
||||||
|
0,0,0,1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static float c_ident_quat[4] = {
|
||||||
|
0, 0, 0, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct constant {
|
||||||
|
float * ptr;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct constant c_constant_table[LINEAR_TYPE_COUNT] = {
|
||||||
|
{ c_ident_mat, MATRIX },
|
||||||
|
{ c_ident_vec, VECTOR4 },
|
||||||
|
{ c_ident_quat, VECTOR4 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stackid_ {
|
||||||
|
uint32_t version:24;
|
||||||
|
uint32_t id:24;
|
||||||
|
uint32_t type : LINEAR_TYPE_BITS_NUM; // 0:matrix 1:vector4 2:float 3:quaternion 4:euler
|
||||||
|
uint32_t persistent:1; // 0: persisent 1: temp
|
||||||
|
};
|
||||||
|
|
||||||
|
union stackid {
|
||||||
|
struct stackid_ s;
|
||||||
|
int64_t i;
|
||||||
|
};
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
lastack_constant(int cons) {
|
||||||
|
if (cons < 0 || cons >= LINEAR_TYPE_COUNT)
|
||||||
|
return 0;
|
||||||
|
union stackid sid;
|
||||||
|
sid.s.version = 0;
|
||||||
|
sid.s.id = cons;
|
||||||
|
sid.s.persistent = 1;
|
||||||
|
sid.s.type = cons;
|
||||||
|
|
||||||
|
return sid.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lastack {
|
||||||
|
int temp_vector_cap;
|
||||||
|
int temp_vector_top;
|
||||||
|
int temp_matrix_cap;
|
||||||
|
int temp_matrix_top;
|
||||||
|
int version;
|
||||||
|
int stack_cap;
|
||||||
|
int stack_top;
|
||||||
|
float * temp_vec;
|
||||||
|
float * temp_mat;
|
||||||
|
struct blob * per_vec;
|
||||||
|
struct blob * per_mat;
|
||||||
|
struct oldpage *old;
|
||||||
|
union stackid *stack;
|
||||||
|
size_t oldpage_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TAG_FREE 0
|
||||||
|
#define TAG_USED 1
|
||||||
|
#define TAG_WILLFREE 2
|
||||||
|
|
||||||
|
struct slot {
|
||||||
|
uint32_t id : 30;
|
||||||
|
uint32_t tag : 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct oldpage {
|
||||||
|
struct oldpage *next;
|
||||||
|
void *page;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct blob {
|
||||||
|
int size;
|
||||||
|
int cap;
|
||||||
|
int freeslot; // free slot list
|
||||||
|
int freelist; // will free
|
||||||
|
char * buffer;
|
||||||
|
struct slot *s;
|
||||||
|
struct oldpage *old;
|
||||||
|
size_t oldpage_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
init_blob_slots(struct blob * B, int slot_beg, int slot_end) {
|
||||||
|
int i;
|
||||||
|
for (i = slot_beg; i < slot_end; ++i) {
|
||||||
|
B->s[i].tag = TAG_FREE;
|
||||||
|
B->s[i].id = i + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
B->s[slot_end - 1].id = 0;
|
||||||
|
B->freeslot = slot_beg + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct blob *
|
||||||
|
blob_new(int size, int cap) {
|
||||||
|
struct blob * B = malloc(sizeof(*B));
|
||||||
|
B->size = size;
|
||||||
|
B->cap = cap;
|
||||||
|
B->freelist = 0; // empty list
|
||||||
|
B->buffer = malloc(size * cap);
|
||||||
|
B->s = malloc(cap * sizeof(*B->s));
|
||||||
|
init_blob_slots(B, 0, cap);
|
||||||
|
B->old = NULL;
|
||||||
|
B->oldpage_size = 0;
|
||||||
|
return B;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
blob_size(struct blob *B) {
|
||||||
|
return sizeof(*B) + (B->size + sizeof(*B->s)) * B->cap + B->oldpage_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_oldpage(struct oldpage *p) {
|
||||||
|
while (p) {
|
||||||
|
struct oldpage *next = p->next;
|
||||||
|
free(p->page);
|
||||||
|
free(p);
|
||||||
|
p = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLOT_INDEX(idx) ((idx)-1)
|
||||||
|
#define SLOT_EMPTY(idx) ((idx)==0)
|
||||||
|
|
||||||
|
static int
|
||||||
|
blob_alloc(struct blob *B, int version) {
|
||||||
|
if (SLOT_EMPTY(B->freeslot)) {
|
||||||
|
struct oldpage * p = malloc(sizeof(*p));
|
||||||
|
p->next = B->old;
|
||||||
|
p->page = B->buffer;
|
||||||
|
B->old = p;
|
||||||
|
|
||||||
|
int cap = B->cap;
|
||||||
|
B->oldpage_size += sizeof(*p) + B->size * cap;
|
||||||
|
|
||||||
|
B->cap *= 2;
|
||||||
|
B->buffer = malloc(B->size * B->cap);
|
||||||
|
memcpy(B->buffer, p->page, B->size * cap);
|
||||||
|
B->s = realloc(B->s, B->cap * sizeof(*B->s));
|
||||||
|
static int alloc_count = 0;
|
||||||
|
alloc_count ++;
|
||||||
|
init_blob_slots(B, cap, B->cap);
|
||||||
|
}
|
||||||
|
int ret = SLOT_INDEX(B->freeslot);
|
||||||
|
struct slot *s = &B->s[ret];
|
||||||
|
B->freeslot = s->id; // next free slot
|
||||||
|
s->tag = TAG_USED;
|
||||||
|
s->id = version;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
blob_address(struct blob *B, int index, int version) {
|
||||||
|
struct slot *s = &B->s[index];
|
||||||
|
if (s->tag != TAG_USED || s->id != version)
|
||||||
|
return NULL;
|
||||||
|
return B->buffer + index * B->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_dealloc(struct blob *B, int index, int version) {
|
||||||
|
struct slot *s = &B->s[index];
|
||||||
|
if (s->tag != TAG_USED || s->id != version)
|
||||||
|
return;
|
||||||
|
s->id = B->freelist;
|
||||||
|
s->tag = TAG_WILLFREE;
|
||||||
|
B->freelist = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_flush(struct blob *B) {
|
||||||
|
int slot = B->freelist;
|
||||||
|
while (slot) {
|
||||||
|
struct slot *s = &B->s[SLOT_INDEX(slot)];
|
||||||
|
s->tag = TAG_FREE;
|
||||||
|
if (SLOT_EMPTY(s->id)) {
|
||||||
|
s->id = B->freeslot;
|
||||||
|
B->freeslot = B->freelist;
|
||||||
|
B->freelist = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
slot = s->id;
|
||||||
|
}
|
||||||
|
free_oldpage(B->old);
|
||||||
|
B->old = NULL;
|
||||||
|
B->oldpage_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_delete(struct blob *B) {
|
||||||
|
if (B) {
|
||||||
|
free(B->buffer);
|
||||||
|
free(B->s);
|
||||||
|
free_oldpage(B->old);
|
||||||
|
free(B);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_list(struct blob *B, const char * h, int list, int tag) {
|
||||||
|
printf("%s ", h);
|
||||||
|
while (!SLOT_EMPTY(list)) {
|
||||||
|
int index = SLOT_INDEX(list);
|
||||||
|
struct slot *s = &B->s[index];
|
||||||
|
if (s->tag == tag) {
|
||||||
|
printf("%d,", SLOT_INDEX(list));
|
||||||
|
} else {
|
||||||
|
printf("%d [ERROR]", SLOT_INDEX(list));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list = s->id;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_print(struct blob *B) {
|
||||||
|
int i;
|
||||||
|
printf("USED: ");
|
||||||
|
for (i=0;i<B->cap;i++) {
|
||||||
|
if (B->s[i].tag == TAG_USED) {
|
||||||
|
printf("%d,", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
print_list(B, "FREE :", B->freeslot, TAG_FREE);
|
||||||
|
print_list(B, "WILLFREE :", B->freelist, TAG_WILLFREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int
|
||||||
|
blob_test_main() {
|
||||||
|
struct blob *B = blob_new(4, 10);
|
||||||
|
int a = blob_alloc(B,1);
|
||||||
|
int b = blob_alloc(B,1);
|
||||||
|
int c = blob_alloc(B,1);
|
||||||
|
blob_print(B);
|
||||||
|
blob_dealloc(B, a, 1);
|
||||||
|
blob_print(B);
|
||||||
|
blob_flush(B);
|
||||||
|
blob_print(B);
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct lastack *
|
||||||
|
lastack_new() {
|
||||||
|
struct lastack * LS = malloc(sizeof(*LS));
|
||||||
|
LS->temp_vector_cap = MINCAP;
|
||||||
|
LS->temp_vector_top = 0;
|
||||||
|
LS->temp_matrix_cap = MINCAP;
|
||||||
|
LS->temp_matrix_top = 0;
|
||||||
|
LS->version = 1; // base 1
|
||||||
|
LS->stack_cap = MINCAP;
|
||||||
|
LS->stack_top = 0;
|
||||||
|
LS->temp_vec = malloc(LS->temp_vector_cap * VECTOR4 * sizeof(float));
|
||||||
|
LS->temp_mat = malloc(LS->temp_matrix_cap * MATRIX * sizeof(float));
|
||||||
|
LS->per_vec = blob_new(VECTOR4 * sizeof(float), MINCAP);
|
||||||
|
LS->per_mat = blob_new(MATRIX * sizeof(float), MINCAP);
|
||||||
|
LS->old = NULL;
|
||||||
|
LS->stack = malloc(LS->stack_cap * sizeof(*LS->stack));
|
||||||
|
LS->oldpage_size = 0;
|
||||||
|
return LS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
lastack_size(struct lastack *LS) {
|
||||||
|
return sizeof(*LS)
|
||||||
|
+ LS->temp_vector_cap * VECTOR4 * sizeof(float)
|
||||||
|
+ LS->temp_matrix_cap * MATRIX * sizeof(float)
|
||||||
|
+ LS->stack_cap * sizeof(*LS->stack)
|
||||||
|
+ blob_size(LS->per_vec)
|
||||||
|
+ blob_size(LS->per_mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_delete(struct lastack *LS) {
|
||||||
|
if (LS == NULL)
|
||||||
|
return;
|
||||||
|
free(LS->temp_vec);
|
||||||
|
free(LS->temp_mat);
|
||||||
|
blob_delete(LS->per_vec);
|
||||||
|
blob_delete(LS->per_mat);
|
||||||
|
free(LS->stack);
|
||||||
|
free_oldpage(LS->old);
|
||||||
|
free(LS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
push_id(struct lastack *LS, union stackid id) {
|
||||||
|
if (LS->stack_top >= LS->stack_cap) {
|
||||||
|
LS->stack = realloc(LS->stack, (LS->stack_cap *= 2) * sizeof(*LS->stack));
|
||||||
|
}
|
||||||
|
LS->stack[LS->stack_top++] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
new_page(struct lastack *LS, void *page, size_t page_size) {
|
||||||
|
struct oldpage * p = malloc(sizeof(*p));
|
||||||
|
p->next = LS->old;
|
||||||
|
p->page = page;
|
||||||
|
LS->old = p;
|
||||||
|
LS->oldpage_size += page_size + sizeof(*p);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_typesize(int type) {
|
||||||
|
const int sizes[LINEAR_TYPE_COUNT] = { 16, 4, 4 };
|
||||||
|
// assert(LINEAR_TYPE_MAT <= type && type < LINEAR_TYPE_COUNT);
|
||||||
|
return sizes[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
lastack_typename(int t) {
|
||||||
|
static const char * type_names[] = {
|
||||||
|
"mat",
|
||||||
|
"v4",
|
||||||
|
"quat",
|
||||||
|
};
|
||||||
|
if (t < 0 || t >= sizeof(type_names)/sizeof(type_names[0]))
|
||||||
|
return "unknown";
|
||||||
|
return type_names[t];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float *
|
||||||
|
check_matrix_pool(struct lastack *LS) {
|
||||||
|
if (LS->temp_matrix_top >= LS->temp_matrix_cap) {
|
||||||
|
size_t sz = LS->temp_matrix_cap * sizeof(float) * MATRIX;
|
||||||
|
void * p = new_page(LS, LS->temp_mat, sz);
|
||||||
|
LS->temp_mat = malloc(sz * 2);
|
||||||
|
memcpy(LS->temp_mat, p, sz);
|
||||||
|
LS->temp_matrix_cap *= 2;
|
||||||
|
}
|
||||||
|
return LS->temp_mat + LS->temp_matrix_top * MATRIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_pushmatrix(struct lastack *LS, const float *mat) {
|
||||||
|
float * pmat = check_matrix_pool(LS);
|
||||||
|
memcpy(pmat, mat, sizeof(float) * MATRIX);
|
||||||
|
union stackid sid;
|
||||||
|
sid.s.type = LINEAR_TYPE_MAT;
|
||||||
|
sid.s.persistent = 0;
|
||||||
|
sid.s.version = LS->version;
|
||||||
|
sid.s.id = LS->temp_matrix_top;
|
||||||
|
push_id(LS, sid);
|
||||||
|
++ LS->temp_matrix_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_pushsrt(struct lastack *LS, const float *s, const float *r, const float *t) {
|
||||||
|
#define NOTIDENTITY (~0)
|
||||||
|
float * mat = check_matrix_pool(LS);
|
||||||
|
uint32_t * mark = (uint32_t *)&mat[3*4];
|
||||||
|
// scale
|
||||||
|
float *scale = &mat[0];
|
||||||
|
if (s == NULL) {
|
||||||
|
scale[0] = 1;
|
||||||
|
scale[1] = 1;
|
||||||
|
scale[2] = 1;
|
||||||
|
scale[3] = 0;
|
||||||
|
mark[0] = 0;
|
||||||
|
} else {
|
||||||
|
float sx = s[0];
|
||||||
|
float sy = s[1];
|
||||||
|
float sz = s[2];
|
||||||
|
scale[0] = sx;
|
||||||
|
scale[1] = sy;
|
||||||
|
scale[2] = sz;
|
||||||
|
scale[3] = 0;
|
||||||
|
if (sx == 1 && sy == 1 && sz == 1) {
|
||||||
|
mark[0] = NOTIDENTITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// rotation
|
||||||
|
float *rotation = &mat[4*1];
|
||||||
|
if (r == NULL || (r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1)) {
|
||||||
|
rotation[0] = 0;
|
||||||
|
rotation[1] = 0;
|
||||||
|
rotation[2] = 0;
|
||||||
|
rotation[3] = 1;
|
||||||
|
mark[1] = 0;
|
||||||
|
} else {
|
||||||
|
rotation[0] = r[0];
|
||||||
|
rotation[1] = r[1];
|
||||||
|
rotation[2] = r[2];
|
||||||
|
rotation[3] = r[3];
|
||||||
|
mark[1] = NOTIDENTITY;
|
||||||
|
}
|
||||||
|
// translate
|
||||||
|
float *translate = &mat[4*2];
|
||||||
|
if (t == NULL || (t[0] == 0 && t[1] == 0 && t[2] == 0)) {
|
||||||
|
translate[0] = 0;
|
||||||
|
translate[1] = 0;
|
||||||
|
translate[2] = 0;
|
||||||
|
translate[3] = 1;
|
||||||
|
mark[2] = 0;
|
||||||
|
} else {
|
||||||
|
translate[0] = t[0];
|
||||||
|
translate[1] = t[1];
|
||||||
|
translate[2] = t[2];
|
||||||
|
translate[3] = 1;
|
||||||
|
mark[2] = NOTIDENTITY;
|
||||||
|
}
|
||||||
|
// mark identity
|
||||||
|
if (mark[0] == 0 && mark[1] == 0 && mark[2] == 0) {
|
||||||
|
mark[3] = 0;
|
||||||
|
} else {
|
||||||
|
mark[3] = NOTIDENTITY;
|
||||||
|
}
|
||||||
|
union stackid sid;
|
||||||
|
sid.s.type = LINEAR_TYPE_MAT;
|
||||||
|
sid.s.persistent = 0;
|
||||||
|
sid.s.version = LS->version;
|
||||||
|
sid.s.id = LS->temp_matrix_top;
|
||||||
|
push_id(LS, sid);
|
||||||
|
++ LS->temp_matrix_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_pushobject(struct lastack *LS, const float *v, int type) {
|
||||||
|
if (type == LINEAR_TYPE_MAT) {
|
||||||
|
lastack_pushmatrix(LS, v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(type >= LINEAR_TYPE_VEC4 && type <= LINEAR_TYPE_QUAT);
|
||||||
|
const int size = lastack_typesize(type);
|
||||||
|
if (LS->temp_vector_top >= LS->temp_vector_cap) {
|
||||||
|
size_t sz = LS->temp_vector_cap * sizeof(float) * VECTOR4;
|
||||||
|
void * p = new_page(LS, LS->temp_vec, sz);
|
||||||
|
LS->temp_vec = malloc(sz * 2);
|
||||||
|
memcpy(LS->temp_vec, p, sz);
|
||||||
|
LS->temp_vector_cap *= 2;
|
||||||
|
}
|
||||||
|
memcpy(LS->temp_vec + LS->temp_vector_top * VECTOR4, v, sizeof(float) * size);
|
||||||
|
union stackid sid;
|
||||||
|
sid.s.type = type;
|
||||||
|
sid.s.persistent = 0;
|
||||||
|
sid.s.version = LS->version;
|
||||||
|
sid.s.id = LS->temp_vector_top;
|
||||||
|
push_id(LS, sid);
|
||||||
|
++ LS->temp_vector_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_pushvec4(struct lastack *LS, const float *vec4) {
|
||||||
|
lastack_pushobject(LS, vec4, LINEAR_TYPE_VEC4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_pushquat(struct lastack *LS, const float *v) {
|
||||||
|
lastack_pushobject(LS, v, LINEAR_TYPE_QUAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float *
|
||||||
|
lastack_value(struct lastack *LS, int64_t ref, int *type) {
|
||||||
|
union stackid sid;
|
||||||
|
sid.i = ref;
|
||||||
|
int id = sid.s.id;
|
||||||
|
int ver = sid.s.version;
|
||||||
|
void * address = NULL;
|
||||||
|
if (type)
|
||||||
|
*type = sid.s.type;
|
||||||
|
if (sid.s.persistent) {
|
||||||
|
if (sid.s.version == 0) {
|
||||||
|
// constant
|
||||||
|
int id = sid.s.id;
|
||||||
|
if (id < 0 || id >= LINEAR_TYPE_COUNT)
|
||||||
|
return NULL;
|
||||||
|
struct constant * c = &c_constant_table[id];
|
||||||
|
return c->ptr;
|
||||||
|
}
|
||||||
|
if (lastack_typesize(sid.s.type) == MATRIX) {
|
||||||
|
address = blob_address( LS->per_mat , id, ver);
|
||||||
|
} else {
|
||||||
|
address = blob_address( LS->per_vec , id, ver);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
} else {
|
||||||
|
if (ver != LS->version) {
|
||||||
|
// version expired
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (lastack_typesize(sid.s.type) == MATRIX) {
|
||||||
|
if (id >= LS->temp_matrix_top) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return LS->temp_mat + id * MATRIX;
|
||||||
|
} else {
|
||||||
|
if (id >= LS->temp_vector_top) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return LS->temp_vec + id * VECTOR4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_pushref(struct lastack *LS, int64_t ref) {
|
||||||
|
union stackid id;
|
||||||
|
id.i = ref;
|
||||||
|
// check alive
|
||||||
|
const void *address = lastack_value(LS, id.i, NULL);
|
||||||
|
if (address == NULL)
|
||||||
|
return 1;
|
||||||
|
push_id(LS, id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_unmark(struct lastack *LS, int64_t markid) {
|
||||||
|
union stackid id;
|
||||||
|
id.i = markid;
|
||||||
|
if (id.s.persistent && id.s.version != 0) {
|
||||||
|
if (lastack_typesize(id.s.type) != MATRIX) {
|
||||||
|
blob_dealloc(LS->per_vec, id.s.id, id.s.version);
|
||||||
|
} else {
|
||||||
|
blob_dealloc(LS->per_mat, id.s.id, id.s.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_isconstant(int64_t markid) {
|
||||||
|
union stackid id;
|
||||||
|
id.i = markid;
|
||||||
|
return (id.s.persistent && id.s.version == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
lastack_mark(struct lastack *LS, int64_t tempid) {
|
||||||
|
if (lastack_isconstant(tempid))
|
||||||
|
return tempid;
|
||||||
|
int t;
|
||||||
|
const float *address = lastack_value(LS, tempid, &t);
|
||||||
|
if (address == NULL) {
|
||||||
|
//printf("--- mark address = null ---");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int id;
|
||||||
|
union stackid sid;
|
||||||
|
sid.s.version = LS->version;
|
||||||
|
sid.s.type = t;
|
||||||
|
if (lastack_typesize(t) != MATRIX) {
|
||||||
|
id = blob_alloc(LS->per_vec, LS->version);
|
||||||
|
void * dest = blob_address(LS->per_vec, id, LS->version);
|
||||||
|
memcpy(dest, address, sizeof(float) * VECTOR4);
|
||||||
|
} else {
|
||||||
|
id = blob_alloc(LS->per_mat, LS->version);
|
||||||
|
void * dest = blob_address(LS->per_mat, id, LS->version);
|
||||||
|
memcpy(dest, address, sizeof(float) * MATRIX);
|
||||||
|
}
|
||||||
|
sid.s.id = id;
|
||||||
|
if (sid.s.id != id) {
|
||||||
|
//printf(" --- s.id(%d) != id(%d) --- \n ",sid.s.id,id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sid.s.persistent = 1;
|
||||||
|
return sid.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_marked(int64_t id, int *type) {
|
||||||
|
union stackid sid;
|
||||||
|
sid.i = id;
|
||||||
|
if (type) {
|
||||||
|
*type = sid.s.type;
|
||||||
|
}
|
||||||
|
return sid.s.persistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_sametype(int64_t id1, int64_t id2) {
|
||||||
|
union stackid sid1,sid2;
|
||||||
|
sid1.i = id1;
|
||||||
|
sid2.i = id2;
|
||||||
|
return sid1.s.type == sid2.s.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
lastack_pop(struct lastack *LS) {
|
||||||
|
if (LS->stack_top <= 0)
|
||||||
|
return 0;
|
||||||
|
union stackid sid = LS->stack[--LS->stack_top];
|
||||||
|
return sid.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
lastack_top(struct lastack *LS) {
|
||||||
|
if (LS->stack_top <= 0)
|
||||||
|
return 0;
|
||||||
|
union stackid sid = LS->stack[LS->stack_top-1];
|
||||||
|
return sid.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
lastack_dup(struct lastack *LS, int index) {
|
||||||
|
if (LS->stack_top < index || index <= 0)
|
||||||
|
return 0;
|
||||||
|
union stackid sid = LS->stack[LS->stack_top-index];
|
||||||
|
push_id(LS, sid);
|
||||||
|
return sid.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
lastack_swap(struct lastack *LS) {
|
||||||
|
if (LS->stack_top <= 1)
|
||||||
|
return 0;
|
||||||
|
union stackid top = LS->stack[LS->stack_top-1];
|
||||||
|
union stackid newtop = LS->stack[LS->stack_top-2];
|
||||||
|
LS->stack[LS->stack_top-2] = top;
|
||||||
|
LS->stack[LS->stack_top-1] = newtop;
|
||||||
|
return newtop.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_reset(struct lastack *LS) {
|
||||||
|
union stackid v;
|
||||||
|
v.s.version = LS->version + 1;
|
||||||
|
if (v.s.version == 0)
|
||||||
|
++ v.s.version;
|
||||||
|
LS->version = v.s.version;
|
||||||
|
LS->stack_top = 0;
|
||||||
|
free_oldpage(LS->old);
|
||||||
|
LS->old = NULL;
|
||||||
|
LS->oldpage_size = 0;
|
||||||
|
blob_flush(LS->per_vec);
|
||||||
|
blob_flush(LS->per_mat);
|
||||||
|
LS->temp_vector_top = 0;
|
||||||
|
LS->temp_matrix_top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_float(const float *address, int n) {
|
||||||
|
int i;
|
||||||
|
for (i=0;i<n-1;i++) {
|
||||||
|
printf("%.3g ", address[i]);
|
||||||
|
}
|
||||||
|
printf("%.3g",address[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_object(const float *address, int id, int type) {
|
||||||
|
switch(type) {
|
||||||
|
case LINEAR_TYPE_NONE:
|
||||||
|
printf("(None");
|
||||||
|
break;
|
||||||
|
case LINEAR_TYPE_MAT:
|
||||||
|
printf("(M%d: ",id);
|
||||||
|
print_float(address, 16);
|
||||||
|
break;
|
||||||
|
case LINEAR_TYPE_VEC4:
|
||||||
|
printf("(V%d: ",id);
|
||||||
|
print_float(address, 4);
|
||||||
|
break;
|
||||||
|
case LINEAR_TYPE_QUAT:
|
||||||
|
printf("(Q%d: ",id);
|
||||||
|
print_float(address, 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("(Invalid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_print(struct lastack *LS) {
|
||||||
|
printf("version = %d\n", LS->version);
|
||||||
|
printf("stack %d/%d:\n", LS->stack_top, LS->stack_cap);
|
||||||
|
int i;
|
||||||
|
for (i=0;i<LS->stack_top;i++) {
|
||||||
|
union stackid id = LS->stack[i];
|
||||||
|
int type;
|
||||||
|
const float *address = lastack_value(LS, id.i, &type);
|
||||||
|
printf("\t[%d]", i);
|
||||||
|
if (id.s.persistent) {
|
||||||
|
printf("version = %d ", id.s.version);
|
||||||
|
}
|
||||||
|
print_object(address, id.s.id, type);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("Persistent Vector ");
|
||||||
|
blob_print(LS->per_vec);
|
||||||
|
printf("Persistent Matrix ");
|
||||||
|
blob_print(LS->per_mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_gettop(struct lastack *LS) {
|
||||||
|
return LS->stack_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lastack_dump(struct lastack *LS, int from) {
|
||||||
|
if (from < 0) {
|
||||||
|
from = LS->stack_top + from;
|
||||||
|
if (from < 0)
|
||||||
|
from = 0;
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
for (i=LS->stack_top-1;i>=from;i--) {
|
||||||
|
union stackid id = LS->stack[i];
|
||||||
|
int type;
|
||||||
|
const float *address = lastack_value(LS, id.i, &type);
|
||||||
|
print_object(address, id.s.id, type);
|
||||||
|
}
|
||||||
|
if (from > 0) {
|
||||||
|
for (i=0;i<from;i++) {
|
||||||
|
printf(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lastack_type(struct lastack *LS, int64_t id) {
|
||||||
|
union stackid sid;
|
||||||
|
sid.i = id;
|
||||||
|
return sid.s.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
lastack_idstring(int64_t id, char tmp[64]) {
|
||||||
|
union stackid sid;
|
||||||
|
sid.i = id;
|
||||||
|
char flags[3] = { 0,0,0 };
|
||||||
|
switch(sid.s.type) {
|
||||||
|
case LINEAR_TYPE_MAT:
|
||||||
|
flags[0] = 'M';
|
||||||
|
break;
|
||||||
|
case LINEAR_TYPE_VEC4:
|
||||||
|
flags[0] = 'V';
|
||||||
|
break;
|
||||||
|
case LINEAR_TYPE_QUAT:
|
||||||
|
flags[0] = 'Q';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flags[0] = '?';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sid.s.persistent) {
|
||||||
|
flags[1] = 'P';
|
||||||
|
}
|
||||||
|
snprintf(tmp, 64, "id=%d version=%d %s",sid.s.id, sid.s.version, flags);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int
|
||||||
|
test_main() {
|
||||||
|
struct lastack *LS = lastack_new();
|
||||||
|
float v[4] = { 1,2,3,4 };
|
||||||
|
float m[16] = {
|
||||||
|
1,0,0,0,
|
||||||
|
0,1,0,0,
|
||||||
|
0,0,1,0,
|
||||||
|
0,0,0,1
|
||||||
|
};
|
||||||
|
lastack_pushvector(LS, v, LINEAR_TYPE_VEC4);
|
||||||
|
int64_t c = lastack_mark(LS);
|
||||||
|
lastack_pushmatrix(LS, m);
|
||||||
|
lastack_pushref(LS, -c);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_print(LS);
|
||||||
|
lastack_reset(LS);
|
||||||
|
lastack_pushref(LS, c);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_dup(LS);
|
||||||
|
lastack_print(LS);
|
||||||
|
lastack_reset(LS);
|
||||||
|
lastack_print(LS);
|
||||||
|
lastack_delete(LS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef linear_algebra_h
|
||||||
|
#define linear_algebra_h
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum LinearType {
|
||||||
|
LINEAR_TYPE_NONE = -1,
|
||||||
|
LINEAR_TYPE_MAT = 0,
|
||||||
|
LINEAR_TYPE_VEC4,
|
||||||
|
LINEAR_TYPE_QUAT,
|
||||||
|
LINEAR_TYPE_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LINEAR_TYPE_BITS_NUM 3
|
||||||
|
|
||||||
|
struct lastack;
|
||||||
|
|
||||||
|
int64_t lastack_constant(int cons);
|
||||||
|
int lastack_isconstant(int64_t id);
|
||||||
|
int lastack_marked(int64_t id, int *type);
|
||||||
|
int lastack_sametype(int64_t id1, int64_t id2);
|
||||||
|
char * lastack_idstring(int64_t id, char tmp[64]); // for debug
|
||||||
|
int lastack_typesize(int type);
|
||||||
|
const char * lastack_typename(int type);
|
||||||
|
|
||||||
|
struct lastack * lastack_new();
|
||||||
|
void lastack_delete(struct lastack *LS);
|
||||||
|
void lastack_pushobject(struct lastack *LS, const float *v, int type);
|
||||||
|
void lastack_pushvec4(struct lastack *LS, const float *v);
|
||||||
|
void lastack_pushquat(struct lastack *LS, const float *v);
|
||||||
|
void lastack_pushmatrix(struct lastack *LS, const float *mat);
|
||||||
|
void lastack_pushsrt(struct lastack *LS, const float *s, const float *r, const float *t);
|
||||||
|
const float * lastack_value(struct lastack *LS, int64_t id, int *type);
|
||||||
|
int lastack_pushref(struct lastack *LS, int64_t id);
|
||||||
|
int64_t lastack_mark(struct lastack *LS, int64_t tempid);
|
||||||
|
void lastack_unmark(struct lastack *LS, int64_t markid);
|
||||||
|
int64_t lastack_pop(struct lastack *LS);
|
||||||
|
int64_t lastack_top(struct lastack *LS);
|
||||||
|
int64_t lastack_dup(struct lastack *LS, int index);
|
||||||
|
int64_t lastack_swap(struct lastack *LS);
|
||||||
|
void lastack_reset(struct lastack *LS);
|
||||||
|
void lastack_print(struct lastack *LS); // for debug, dump all stack
|
||||||
|
int lastack_gettop(struct lastack *LS); // for debug, get stack length
|
||||||
|
void lastack_dump(struct lastack *LS, int from); // for debug, dump top values
|
||||||
|
int lastack_type(struct lastack *LS, int64_t id);
|
||||||
|
size_t lastack_size(struct lastack *LS);
|
||||||
|
|
||||||
|
static inline int lastack_is_vec_type(int type) {
|
||||||
|
return (type == LINEAR_TYPE_VEC4) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef math3d_lua_binding_h
|
||||||
|
#define math3d_lua_binding_h
|
||||||
|
|
||||||
|
#include "linalg.h"
|
||||||
|
#include <lua.h>
|
||||||
|
|
||||||
|
struct boxstack {
|
||||||
|
struct lastack *LS;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct refobject {
|
||||||
|
int64_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MATH3D_STACK "_MATHSTACK"
|
||||||
|
|
||||||
|
int math3d_homogeneous_depth();
|
||||||
|
|
||||||
|
// binding functions
|
||||||
|
|
||||||
|
const float * math3d_from_lua(lua_State *L, struct lastack *LS, int index, int type);
|
||||||
|
const float * math3d_from_lua_id(lua_State *L, struct lastack *LS, int index, int *type);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef math3d_func_h
|
||||||
|
#define math3d_func_h
|
||||||
|
|
||||||
|
#include "linalg.h"
|
||||||
|
|
||||||
|
#define LINEAR_TYPE_NUM LINEAR_TYPE_COUNT
|
||||||
|
|
||||||
|
// math functions
|
||||||
|
|
||||||
|
void math3d_make_srt(struct lastack *LS, const float *s, const float *r, const float *t);
|
||||||
|
void math3d_make_quat_from_euler(struct lastack *LS, float x, float y, float z);
|
||||||
|
void math3d_make_quat_from_axis(struct lastack *LS, const float *axis, float radian);
|
||||||
|
int math3d_mul_object(struct lastack *LS, const float *lval, const float *rval, int ltype, int rtype, float tmp[16]);
|
||||||
|
void math3d_add_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]);
|
||||||
|
void math3d_sub_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]);
|
||||||
|
void math3d_decompose_matrix(struct lastack *LS, const float *mat);
|
||||||
|
void math3d_decompose_rot(const float mat[16], float quat[4]);
|
||||||
|
int math3d_decompose_scale(const float mat[16], float scale[4]);
|
||||||
|
void math3d_quat_to_matrix(struct lastack *LS, const float quat[4]);
|
||||||
|
void math3d_matrix_to_quat(struct lastack *LS, const float mat[16]);
|
||||||
|
float math3d_length(const float *v3);
|
||||||
|
void math3d_floor(struct lastack *LS, const float v[4]);
|
||||||
|
void math3d_ceil(struct lastack *LS, const float v[4]);
|
||||||
|
float math3d_dot(const float v1[4], const float v2[4]);
|
||||||
|
void math3d_cross(struct lastack *LS, const float v1[4], const float v2[4]);
|
||||||
|
void math3d_mulH(struct lastack *LS, const float mat[16], const float vec[4]);
|
||||||
|
void math3d_normalize_vector(struct lastack *LS, const float v[4]);
|
||||||
|
void math3d_normalize_quat(struct lastack *LS, const float v[4]);
|
||||||
|
void math3d_inverse_matrix(struct lastack *LS, const float mat[16]);
|
||||||
|
void math3d_inverse_quat(struct lastack *LS, const float quat[4]);
|
||||||
|
void math3d_transpose_matrix(struct lastack *LS, const float mat[16]);
|
||||||
|
void math3d_lookat_matrix(struct lastack *LS, int direction, const float eye[3], const float at[3], const float *up);
|
||||||
|
void math3d_reciprocal(struct lastack *LS, const float v[4]);
|
||||||
|
void math3d_quat_to_viewdir(struct lastack *LS, const float q[4]);
|
||||||
|
void math3d_rotmat_to_viewdir(struct lastack *LS, const float m[16]);
|
||||||
|
void math3d_viewdir_to_quat(struct lastack *LS, const float v[3]);
|
||||||
|
void math3d_frustumLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth);
|
||||||
|
void math3d_orthoLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth);
|
||||||
|
void math3d_base_axes(struct lastack *LS, const float forward[4]);
|
||||||
|
void math3d_quat_transform(struct lastack *LS, const float quat[4], const float v[4]);
|
||||||
|
void math3d_rotmat_transform(struct lastack *LS, const float mat[16], const float v[4]);
|
||||||
|
void math3d_minmax(struct lastack *LS, const float mat[16], const float v[4], float minv[4], float maxv[4]);
|
||||||
|
void math3d_lerp(struct lastack *LS, const float v0[4], const float v1[4], float ratio, float r[4]);
|
||||||
|
void math3d_dir2radian(struct lastack *LS, const float v[4], float radians[2]);
|
||||||
|
#endif
|
||||||
@ -0,0 +1,538 @@
|
|||||||
|
#define LUA_LIB
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "math3d.h"
|
||||||
|
#include "linalg.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SET_Mat = 0x01,
|
||||||
|
SET_Vec = 0x02,
|
||||||
|
SET_Array = 0x10,
|
||||||
|
SET_Unknown,
|
||||||
|
}StackElemType;
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
get_pointer(lua_State *L, struct lastack *LS, int index, int type) {
|
||||||
|
return (void *)math3d_from_lua(L, LS, index, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
getopt_pointer(lua_State *L, struct lastack *LS, int index, int type) {
|
||||||
|
if (lua_isnoneornil(L, index)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return get_pointer(L, LS, index, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
get_pointer_variant(lua_State *L, struct lastack *LS, int index, int elemtype) {
|
||||||
|
if (elemtype & SET_Mat) {
|
||||||
|
return get_pointer(L, LS, index, LINEAR_TYPE_MAT);
|
||||||
|
} else {
|
||||||
|
return get_pointer(L, LS, index, LINEAR_TYPE_VEC4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1 mathstack
|
||||||
|
// upvalue2 cfunction
|
||||||
|
// upvalue3 from
|
||||||
|
static int
|
||||||
|
lmatrix_adapter_1(lua_State *L) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
int from = lua_tointeger(L, lua_upvalueindex(3));
|
||||||
|
void * v = get_pointer(L, LS, from, LINEAR_TYPE_MAT);
|
||||||
|
lua_settop(L, from-1);
|
||||||
|
lua_pushlightuserdata(L, v);
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lmatrix_adapter_2(lua_State *L) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
int from = lua_tointeger(L, lua_upvalueindex(3));
|
||||||
|
void * v1 = getopt_pointer(L, LS, from, LINEAR_TYPE_MAT);
|
||||||
|
void * v2 = getopt_pointer(L, LS, from+1, LINEAR_TYPE_MAT);
|
||||||
|
lua_settop(L, from-1);
|
||||||
|
if (v1) {
|
||||||
|
lua_pushlightuserdata(L, v1);
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
if (v2) {
|
||||||
|
lua_pushlightuserdata(L, v2);
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lmatrix_adapter_var(lua_State *L) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
int from = lua_tointeger(L, lua_upvalueindex(3));
|
||||||
|
int i;
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
for (i=from;i<=top;i++) {
|
||||||
|
void * v = getopt_pointer(L, LS, i, LINEAR_TYPE_MAT);
|
||||||
|
if (v) {
|
||||||
|
lua_pushlightuserdata(L, v);
|
||||||
|
lua_replace(L, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1 : userdata mathstack
|
||||||
|
// cfunction original function
|
||||||
|
// integer from
|
||||||
|
// integer n
|
||||||
|
static int
|
||||||
|
lbind_matrix(lua_State *L) {
|
||||||
|
if (!lua_iscfunction(L, 1))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
if (lua_getupvalue(L, 1, 1) != NULL)
|
||||||
|
luaL_error(L, "Only support light cfunction");
|
||||||
|
int from = luaL_checkinteger(L, 2);
|
||||||
|
int n = luaL_optinteger(L, 3, 0);
|
||||||
|
lua_CFunction f;
|
||||||
|
switch (n) {
|
||||||
|
case 0:
|
||||||
|
f = lmatrix_adapter_var;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
f = lmatrix_adapter_1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
f = lmatrix_adapter_2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return luaL_error(L, "Only support 1,2,0(vararg) now");
|
||||||
|
}
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushinteger(L, from);
|
||||||
|
lua_pushcclosure(L, f, 4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lvector(lua_State *L) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
const int from = lua_tointeger(L, lua_upvalueindex(3));
|
||||||
|
|
||||||
|
const int top = lua_gettop(L);
|
||||||
|
|
||||||
|
int ii;
|
||||||
|
|
||||||
|
for (ii = from; ii <= top; ++ii) {
|
||||||
|
if (!lua_isnil(L, ii)) {
|
||||||
|
void* p = get_pointer(L, LS, ii, LINEAR_TYPE_VEC4);
|
||||||
|
lua_pushlightuserdata(L, p);
|
||||||
|
lua_replace(L, ii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lbind_vector(lua_State *L) {
|
||||||
|
if (!lua_iscfunction(L, 1))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
if (lua_getupvalue(L, 1, 1) != NULL)
|
||||||
|
luaL_error(L, "Only support light cfunction");
|
||||||
|
|
||||||
|
luaL_checkinteger(L, 2);
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_pushvalue(L, 1); // cfunction
|
||||||
|
lua_pushvalue(L, 2); // from
|
||||||
|
lua_pushcclosure(L, lvector, 3);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
check_elem_type(lua_State *L, struct lastack *LS, int index) {
|
||||||
|
if (lua_type(L, index) == LUA_TTABLE) {
|
||||||
|
const int fieldtype = lua_getfield(L, index, "n");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
if (fieldtype != LUA_TNIL){
|
||||||
|
const int elemtype = lua_geti(L, index, 1);
|
||||||
|
if (elemtype != LUA_TTABLE) {
|
||||||
|
int type;
|
||||||
|
math3d_from_lua_id(L, LS, -1, &type);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return SET_Array | (type == LINEAR_TYPE_MAT ? SET_Mat : SET_Vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return SET_Array | (lua_rawlen(L, index) >= 12 ? SET_Mat : SET_Vec);
|
||||||
|
}
|
||||||
|
return lua_rawlen(L, index) >= 12 ? SET_Mat : SET_Vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
int type;
|
||||||
|
math3d_from_lua_id(L, LS, index, &type);
|
||||||
|
return type == LINEAR_TYPE_MAT ? SET_Mat : SET_Vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unpack_table_on_stack(lua_State *L, struct lastack *LS, int from, int top, int elemtype) {
|
||||||
|
int stackidx;
|
||||||
|
for (stackidx = from; stackidx <= top; ++stackidx) {
|
||||||
|
if (lua_getfield(L, stackidx, "n") != LUA_TNIL) {
|
||||||
|
const int num = (int)lua_tointeger(L, -1);
|
||||||
|
lua_pop(L, 1); // pop 'n'
|
||||||
|
|
||||||
|
const int tablenum = (int)lua_rawlen(L, stackidx);
|
||||||
|
if (num != tablenum) {
|
||||||
|
luaL_error(L, "'n' field: %d not equal to table count: %d", num, tablenum);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tblidx;
|
||||||
|
for (tblidx = 0; tblidx < num; ++tblidx) {
|
||||||
|
lua_geti(L, stackidx, tblidx + 1);
|
||||||
|
void * v = get_pointer_variant(L, LS, -1, elemtype);
|
||||||
|
if (v) {
|
||||||
|
lua_pop(L, 1); // pop lua_geti value
|
||||||
|
lua_pushlightuserdata(L, v);
|
||||||
|
} else {
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// v == NULL will not pop, make it in the stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ii;
|
||||||
|
for (ii = 0; ii <= top - from; ++ii) {
|
||||||
|
lua_remove(L, from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_stack_value(lua_State *L, struct lastack *LS, int from, int top, int elemtype) {
|
||||||
|
int i;
|
||||||
|
for (i = from; i <= top; i++) {
|
||||||
|
void * v = get_pointer_variant(L, LS, i, elemtype);
|
||||||
|
if (v) {
|
||||||
|
lua_pushlightuserdata(L, v);
|
||||||
|
lua_replace(L, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1 mathstack
|
||||||
|
// upvalue2 matrix cfunction
|
||||||
|
// upvalue3 vector cfunction
|
||||||
|
// upvalue4 integer from
|
||||||
|
static int
|
||||||
|
lvariant(lua_State *L) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
const int from = lua_tointeger(L, lua_upvalueindex(4));
|
||||||
|
const int top = lua_gettop(L);
|
||||||
|
const uint8_t elemtype = check_elem_type(L, LS, from);
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex((elemtype & SET_Mat) ? 2 : 3));
|
||||||
|
if (elemtype & SET_Array) {
|
||||||
|
unpack_table_on_stack(L, LS, from, top, elemtype);
|
||||||
|
} else {
|
||||||
|
convert_stack_value(L, LS, from, top, elemtype);
|
||||||
|
}
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1 : userdata mathstack
|
||||||
|
// cfunction original function for matrix
|
||||||
|
// cfunction original function for vector
|
||||||
|
// integer from
|
||||||
|
static int
|
||||||
|
lbind_variant(lua_State *L) {
|
||||||
|
if (!lua_iscfunction(L, 1))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
if (lua_getupvalue(L, 1, 1) != NULL)
|
||||||
|
luaL_error(L, "Only support light cfunction");
|
||||||
|
if (!lua_iscfunction(L, 2))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
if (lua_getupvalue(L, 2, 1) != NULL)
|
||||||
|
luaL_error(L, "Only support light cfunction");
|
||||||
|
luaL_checkinteger(L, 3);
|
||||||
|
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushvalue(L, 3);
|
||||||
|
|
||||||
|
lua_pushcclosure(L, lvariant, 4);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lformat(lua_State *L, const char *format) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
int from = lua_tointeger(L, lua_upvalueindex(4));
|
||||||
|
int i;
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
void *v = NULL;
|
||||||
|
for (i=0;format[i];i++) {
|
||||||
|
int index = from + i;
|
||||||
|
if (index > top)
|
||||||
|
luaL_error(L, "Invalid format string %s", format);
|
||||||
|
switch(format[i]) {
|
||||||
|
case 'm':
|
||||||
|
v = get_pointer(L, LS, index, LINEAR_TYPE_MAT);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
v = get_pointer(L, LS, index, LINEAR_TYPE_VEC4);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
v = get_pointer(L, LS, index, LINEAR_TYPE_QUAT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
luaL_error(L, "Invalid format string %s", format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lua_pushlightuserdata(L, v);
|
||||||
|
lua_replace(L, index);
|
||||||
|
}
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lformat_function(lua_State *L) {
|
||||||
|
lua_CFunction getformat = lua_tocfunction(L, lua_upvalueindex(3));
|
||||||
|
if (getformat(L) != 1 || lua_type(L, -1) != LUA_TLIGHTUSERDATA)
|
||||||
|
luaL_error(L, "Invalid format C function");
|
||||||
|
const char *format = (const char *)lua_touserdata(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return lformat(L, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lformat_string(lua_State *L) {
|
||||||
|
const char *format = lua_tostring(L, lua_upvalueindex(3));
|
||||||
|
return lformat(L, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1: userdata mathstack
|
||||||
|
// cfunction original function
|
||||||
|
// cfunction function return (void *)format
|
||||||
|
// integer from
|
||||||
|
static int
|
||||||
|
lbind_format(lua_State *L) {
|
||||||
|
if (!lua_iscfunction(L, 1))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
if (lua_getupvalue(L, 1, 1) != NULL)
|
||||||
|
luaL_error(L, "Only support light cfunction");
|
||||||
|
int string_version = 0;
|
||||||
|
if (lua_isstring(L, 2)) {
|
||||||
|
string_version = 1;
|
||||||
|
} else if (!lua_iscfunction(L, 2)) {
|
||||||
|
return luaL_error(L, "need a c format function or string");
|
||||||
|
}
|
||||||
|
if (lua_getupvalue(L, 2, 1) != NULL)
|
||||||
|
luaL_error(L, "Only support light cfunction");
|
||||||
|
luaL_checkinteger(L, 3);
|
||||||
|
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushvalue(L, 3);
|
||||||
|
|
||||||
|
if (string_version) {
|
||||||
|
lua_pushcclosure(L, lformat_string, 4);
|
||||||
|
} else {
|
||||||
|
lua_pushcclosure(L, lformat_function, 4);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stack_buf {
|
||||||
|
float mat[16];
|
||||||
|
struct stack_buf *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_n(lua_State *L, int n, struct stack_buf *prev) {
|
||||||
|
if (n == 0) {
|
||||||
|
struct lastack *LS = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
size_t sz = 0;
|
||||||
|
const char *format = lua_tolstring(L, lua_upvalueindex(3), &sz);
|
||||||
|
int ret = f(L);
|
||||||
|
if (ret == 0) {
|
||||||
|
lua_settop(L, 0);
|
||||||
|
} else {
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
if (ret != top) {
|
||||||
|
if (ret < top && ret != 0) {
|
||||||
|
int remove = top-ret;
|
||||||
|
lua_rotate(L, 1, -remove);
|
||||||
|
}
|
||||||
|
lua_settop(L, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
luaL_checkstack(L, (int)sz, NULL);
|
||||||
|
int i = (int)sz - 1;
|
||||||
|
while (prev) {
|
||||||
|
switch(format[i]) {
|
||||||
|
case 'm':
|
||||||
|
lastack_pushmatrix(LS, prev->mat);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
lastack_pushvec4(LS, prev->mat);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
lastack_pushquat(LS, prev->mat);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
luaL_error(L,"Invalid getter format %s", format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int64_t id = lastack_pop(LS);
|
||||||
|
lua_pushlightuserdata(L, (void *)id);
|
||||||
|
lua_insert(L, ret+1);
|
||||||
|
|
||||||
|
prev = prev->prev;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
return ret + (int)sz;
|
||||||
|
}
|
||||||
|
struct stack_buf buf;
|
||||||
|
buf.prev = prev;
|
||||||
|
lua_pushlightuserdata(L, (void *)buf.mat);
|
||||||
|
return get_n(L, n-1, &buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lgetter(lua_State *L) {
|
||||||
|
size_t n = 0;
|
||||||
|
lua_tolstring(L, lua_upvalueindex(3), &n);
|
||||||
|
luaL_checkstack(L, (int)(n + LUA_MINSTACK), NULL);
|
||||||
|
return get_n(L, (int)n, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1 : userdata mathstack
|
||||||
|
// cfunction original getter
|
||||||
|
// string format "mvq" , m for matrix, v for vector4, q for quat
|
||||||
|
static int
|
||||||
|
lbind_getter(lua_State *L) {
|
||||||
|
if (!lua_iscfunction(L, 1))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
luaL_checkstring(L, 2);
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushcclosure(L, lgetter, 3);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loutput_object(lua_State *L, int ltype) {
|
||||||
|
lua_CFunction f = lua_tocfunction(L, lua_upvalueindex(2));
|
||||||
|
int retn = f(L);
|
||||||
|
int from = lua_tointeger(L, lua_upvalueindex(3));
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
if (retn > from) {
|
||||||
|
lua_settop(L, retn);
|
||||||
|
top = retn;
|
||||||
|
}
|
||||||
|
from = top - retn + from;
|
||||||
|
int i;
|
||||||
|
struct lastack *LS = (struct lastack *)lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
|
||||||
|
for (i=from;i<=top;i++) {
|
||||||
|
if (lua_type(L, i) != LUA_TLIGHTUSERDATA) {
|
||||||
|
return luaL_error(L, "ret %d should be a lightuserdata", i);
|
||||||
|
}
|
||||||
|
const float *v = (const float *)lua_touserdata(L, i);
|
||||||
|
lastack_pushobject(LS, v, ltype);
|
||||||
|
lua_pushlightuserdata(L, (void *)(lastack_pop(LS)));
|
||||||
|
lua_replace(L, i);
|
||||||
|
}
|
||||||
|
return retn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loutput_matrix(lua_State *L) {
|
||||||
|
return loutput_object(L, LINEAR_TYPE_MAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loutput_vector(lua_State *L) {
|
||||||
|
return loutput_object(L, LINEAR_TYPE_VEC4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
loutput_quat(lua_State *L) {
|
||||||
|
return loutput_object(L, LINEAR_TYPE_QUAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upvalue1 : userdata mathstack
|
||||||
|
// cfunction original output
|
||||||
|
// integer from
|
||||||
|
static int
|
||||||
|
lbind_output(lua_State *L, lua_CFunction output_func) {
|
||||||
|
if (!lua_iscfunction(L, 1))
|
||||||
|
return luaL_error(L, "need a c function");
|
||||||
|
luaL_checkinteger(L, 2);
|
||||||
|
lua_pushvalue(L, lua_upvalueindex(1));
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushcclosure(L, output_func, 3);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lbind_output_matrix(lua_State *L) {
|
||||||
|
return lbind_output(L, loutput_matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lbind_output_vector(lua_State *L) {
|
||||||
|
return lbind_output(L, loutput_vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lbind_output_quat(lua_State *L) {
|
||||||
|
return lbind_output(L, loutput_quat);
|
||||||
|
}
|
||||||
|
|
||||||
|
LUAMOD_API int
|
||||||
|
luaopen_math3d_adapter(lua_State *L) {
|
||||||
|
luaL_checkversion(L);
|
||||||
|
|
||||||
|
luaL_Reg l[] = {
|
||||||
|
{ "matrix", lbind_matrix },
|
||||||
|
{ "vector", lbind_vector},
|
||||||
|
{ "variant", lbind_variant },
|
||||||
|
{ "format", lbind_format },
|
||||||
|
{ "getter", lbind_getter },
|
||||||
|
{ "output_matrix", lbind_output_matrix },
|
||||||
|
{ "output_vector", lbind_output_vector },
|
||||||
|
{ "output_quat", lbind_output_quat },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
luaL_newlibtable(L, l);
|
||||||
|
|
||||||
|
if (lua_getfield(L, LUA_REGISTRYINDEX, MATH3D_STACK) != LUA_TUSERDATA) {
|
||||||
|
return luaL_error(L, "request 'math3d' first");
|
||||||
|
}
|
||||||
|
struct boxstack * bs = lua_touserdata(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushlightuserdata(L, bs->LS);
|
||||||
|
|
||||||
|
luaL_setfuncs(L,l,1);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@ -0,0 +1,412 @@
|
|||||||
|
#define LUA_LIB
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "linalg.h"
|
||||||
|
#include "math3dfunc.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
#include <glm/ext/scalar_relational.hpp>
|
||||||
|
#include <glm/ext/vector_relational.hpp>
|
||||||
|
#include <glm/gtx/euler_angles.hpp>
|
||||||
|
#include <glm/ext/vector_common.hpp>
|
||||||
|
|
||||||
|
static const glm::vec4 XAXIS(1, 0, 0, 0);
|
||||||
|
static const glm::vec4 YAXIS(0, 1, 0, 0);
|
||||||
|
static const glm::vec4 ZAXIS(0, 0, 1, 0);
|
||||||
|
static const glm::vec4 WAXIS(0, 0, 0, 1);
|
||||||
|
|
||||||
|
static const glm::vec4 NXAXIS = -XAXIS;
|
||||||
|
static const glm::vec4 NYAXIS = -YAXIS;
|
||||||
|
static const glm::vec4 NZAXIS = -ZAXIS;
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_make_srt(struct lastack *LS, const float *scale, const float *rot, const float *translate) {
|
||||||
|
glm::mat4x4 srt;
|
||||||
|
if (scale) {
|
||||||
|
srt = glm::mat4x4(1);
|
||||||
|
srt[0][0] = scale[0];
|
||||||
|
srt[1][1] = scale[1];
|
||||||
|
srt[2][2] = scale[2];
|
||||||
|
}
|
||||||
|
if (rot) {
|
||||||
|
const glm::quat * q = (const glm::quat *)rot;
|
||||||
|
if (scale) {
|
||||||
|
srt = glm::mat4x4(*q) * srt;
|
||||||
|
} else {
|
||||||
|
srt = glm::mat4x4(*q);
|
||||||
|
}
|
||||||
|
} else if (scale == NULL) {
|
||||||
|
srt = glm::mat4x4(1);
|
||||||
|
}
|
||||||
|
if (translate) {
|
||||||
|
srt[3][0] = translate[0];
|
||||||
|
srt[3][1] = translate[1];
|
||||||
|
srt[3][2] = translate[2];
|
||||||
|
srt[3][3] = 1;
|
||||||
|
}
|
||||||
|
lastack_pushmatrix(LS, &srt[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_make_quat_from_euler(struct lastack *LS, float x, float y, float z) {
|
||||||
|
glm::vec3 r(x,y,z);
|
||||||
|
glm::quat q(r);
|
||||||
|
lastack_pushquat(LS, &q[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_make_quat_from_axis(struct lastack *LS, const float *axis, float radian) {
|
||||||
|
glm::vec3 a(axis[0],axis[1],axis[2]);
|
||||||
|
glm::quat q = glm::angleAxis(radian, a);
|
||||||
|
|
||||||
|
lastack_pushquat(LS, &q[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BINTYPE(v1, v2) (((v1) << LINEAR_TYPE_BITS_NUM) + (v2))
|
||||||
|
#define MAT(v) (*(const glm::mat4x4 *)(v))
|
||||||
|
#define VEC(v) (*(const glm::vec4 *)(v))
|
||||||
|
#define VEC3(v) (*(const glm::vec3 *)(v))
|
||||||
|
#define QUAT(v) (*(const glm::quat *)(v))
|
||||||
|
|
||||||
|
int
|
||||||
|
math3d_mul_object(struct lastack *LS, const float *val0, const float *val1, int ltype, int rtype, float tmp[16]) {
|
||||||
|
int type = BINTYPE(ltype, rtype);
|
||||||
|
|
||||||
|
glm::mat4x4 &mat = *(glm::mat4x4 *)tmp;
|
||||||
|
glm::vec4 &vec = *(glm::vec4 *)tmp;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case BINTYPE(LINEAR_TYPE_MAT,LINEAR_TYPE_MAT):
|
||||||
|
mat = MAT(val0) * MAT(val1);
|
||||||
|
return LINEAR_TYPE_MAT;
|
||||||
|
case BINTYPE(LINEAR_TYPE_VEC4, LINEAR_TYPE_NUM):
|
||||||
|
vec = VEC(val0) * val1[0];
|
||||||
|
return LINEAR_TYPE_VEC4;
|
||||||
|
case BINTYPE(LINEAR_TYPE_NUM, LINEAR_TYPE_VEC4):
|
||||||
|
vec = val0[0] * VEC(val1);
|
||||||
|
return LINEAR_TYPE_VEC4;
|
||||||
|
case BINTYPE(LINEAR_TYPE_QUAT, LINEAR_TYPE_QUAT): {
|
||||||
|
glm::quat &quat = *(glm::quat *)tmp;
|
||||||
|
quat = QUAT(val0) * QUAT(val1);
|
||||||
|
return LINEAR_TYPE_QUAT;
|
||||||
|
}
|
||||||
|
case BINTYPE(LINEAR_TYPE_VEC4, LINEAR_TYPE_VEC4):
|
||||||
|
vec = VEC(val0) * VEC(val1);
|
||||||
|
return LINEAR_TYPE_VEC4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LINEAR_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_add_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]){
|
||||||
|
*(glm::vec4*)r = VEC(lhs) + VEC(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_sub_vec(struct lastack *LS, const float lhs[4], const float rhs[4], float r[4]){
|
||||||
|
*(glm::vec4*)r = VEC(lhs) - VEC(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// epsilon for pow2
|
||||||
|
//#define EPSILON 0.00001f
|
||||||
|
// glm::equal(dot , 1.0f, EPSILON)
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
equal_one(float f) {
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t n;
|
||||||
|
} u;
|
||||||
|
u.f = f;
|
||||||
|
return ((u.n + 0x1f) & ~0x3f) == 0x3f800000; // float 1
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
math3d_decompose_scale(const float mat[16], float scale[4]) {
|
||||||
|
int ii;
|
||||||
|
scale[3] = 0;
|
||||||
|
for (ii = 0; ii < 3; ++ii) {
|
||||||
|
const float * v = (const float *)&MAT(mat)[ii];
|
||||||
|
float dot = glm::dot(VEC3(v),VEC3(v));
|
||||||
|
if (equal_one(dot)) {
|
||||||
|
scale[ii] = 1.0f;
|
||||||
|
} else {
|
||||||
|
scale[ii] = sqrtf(dot);
|
||||||
|
if (scale[ii] == 0) {
|
||||||
|
// invalid scale, use 1 instead
|
||||||
|
scale[0] = scale[1] = scale[2] = 1.0f;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scale[0] == 1.0f && scale[1] == 1.0f && scale[2] == 1.0f) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_decompose_rot(const float mat[16], float quat[4]) {
|
||||||
|
glm::quat &q = *(glm::quat *)quat;
|
||||||
|
glm::mat3x3 rotMat(MAT(mat));
|
||||||
|
float scale[4];
|
||||||
|
if (math3d_decompose_scale(mat, scale) == 0) {
|
||||||
|
int ii;
|
||||||
|
for (ii = 0; ii < 3; ++ii) {
|
||||||
|
rotMat[ii] /= scale[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q = glm::quat_cast(rotMat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_decompose_matrix(struct lastack *LS, const float *mat) {
|
||||||
|
const glm::mat4x4 &m = *(const glm::mat4x4 *)mat;
|
||||||
|
float trans[4] = { m[3][0] , m[3][1], m[3][2], 1 };
|
||||||
|
float scale[4];
|
||||||
|
glm::mat3x3 rotMat(m);
|
||||||
|
if (!math3d_decompose_scale(mat, scale)) {
|
||||||
|
int ii;
|
||||||
|
for (ii = 0; ii < 3; ++ii) {
|
||||||
|
rotMat[ii] /= scale[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glm::quat q = glm::quat_cast(rotMat);
|
||||||
|
lastack_pushvec4(LS, trans);
|
||||||
|
lastack_pushquat(LS, &q.x);
|
||||||
|
lastack_pushvec4(LS, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
math3d_length(const float *v) {
|
||||||
|
return glm::length(VEC3(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_floor(struct lastack *LS, const float v[4]) {
|
||||||
|
glm::vec4 vv(glm::floor(VEC3(v)), 0.f);
|
||||||
|
lastack_pushvec4(LS, &vv.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_ceil(struct lastack *LS, const float v[4]) {
|
||||||
|
glm::vec4 vv(glm::ceil(VEC3(v)), 0.f);
|
||||||
|
lastack_pushvec4(LS, &vv.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
math3d_dot(const float v1[4], const float v2[4]) {
|
||||||
|
return glm::dot(VEC3(v1), VEC3(v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_cross(struct lastack *LS, const float v1[4], const float v2[4]) {
|
||||||
|
glm::vec4 r(glm::cross(VEC3(v1), VEC3(v2)), 0);
|
||||||
|
lastack_pushvec4(LS, &r.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_mulH(struct lastack *LS, const float mat[16], const float vec[4]) {
|
||||||
|
glm::vec4 r;
|
||||||
|
|
||||||
|
if (vec[3] != 1.f){
|
||||||
|
float tmp[4] = { vec[0], vec[1], vec[2], 1 };
|
||||||
|
r = MAT(mat) * VEC(tmp);
|
||||||
|
} else {
|
||||||
|
r = MAT(mat) * VEC(vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.w != 0) {
|
||||||
|
r /= fabs(r.w);
|
||||||
|
r.w = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastack_pushvec4(LS, &r.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_normalize_vector(struct lastack *LS, const float v[4]) {
|
||||||
|
glm::vec4 r(glm::normalize(VEC3(v)), v[3]);
|
||||||
|
lastack_pushvec4(LS, &r.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_normalize_quat(struct lastack *LS, const float v[4]) {
|
||||||
|
glm::quat q = glm::normalize(QUAT(v));
|
||||||
|
lastack_pushquat(LS, &q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_transpose_matrix(struct lastack *LS, const float mat[16]) {
|
||||||
|
glm::mat4x4 r = glm::transpose(MAT(mat));
|
||||||
|
lastack_pushmatrix(LS, &r[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_inverse_matrix(struct lastack *LS, const float mat[16]) {
|
||||||
|
glm::mat4x4 r = glm::inverse(MAT(mat));
|
||||||
|
lastack_pushmatrix(LS, &r[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_inverse_quat(struct lastack *LS, const float quat[4]) {
|
||||||
|
glm::quat q = glm::inverse(QUAT(quat));
|
||||||
|
lastack_pushquat(LS, &q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_lookat_matrix(struct lastack *LS, int direction, const float eye[3], const float at[3], const float *up) {
|
||||||
|
glm::mat4x4 m;
|
||||||
|
if (up == NULL) {
|
||||||
|
static const float default_up[3] = {0,1,0};
|
||||||
|
up = default_up;
|
||||||
|
}
|
||||||
|
if (direction) {
|
||||||
|
const glm::vec3 vat = VEC3(eye) + VEC3(at);
|
||||||
|
m = glm::lookAtLH(VEC3(eye), vat, VEC3(up));
|
||||||
|
} else {
|
||||||
|
m = glm::lookAtLH(VEC3(eye), VEC3(at), VEC3(up));
|
||||||
|
}
|
||||||
|
lastack_pushmatrix(LS, &m[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_quat_to_matrix(struct lastack *LS, const float quat[4]) {
|
||||||
|
glm::mat4x4 m = glm::mat4x4(QUAT(quat));
|
||||||
|
lastack_pushmatrix(LS, &m[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_matrix_to_quat(struct lastack *LS, const float mat[16]) {
|
||||||
|
glm::quat q = glm::quat_cast(MAT(mat));
|
||||||
|
lastack_pushquat(LS, &q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_reciprocal(struct lastack *LS, const float v[4]) {
|
||||||
|
glm::vec4 vv = VEC(v);
|
||||||
|
vv = 1.f / vv;
|
||||||
|
vv[3] = v[3];
|
||||||
|
lastack_pushvec4(LS, &vv.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_quat_to_viewdir(struct lastack *LS, const float q[4]) {
|
||||||
|
glm::vec4 d = glm::rotate(QUAT(q), glm::vec4(0, 0, 1, 0));
|
||||||
|
lastack_pushvec4(LS, &d.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_rotmat_to_viewdir(struct lastack *LS, const float m[16]) {
|
||||||
|
glm::vec4 d = MAT(m) * glm::vec4(0, 0, 1, 0);
|
||||||
|
lastack_pushvec4(LS, &d.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_viewdir_to_quat(struct lastack *LS, const float v[3]) {
|
||||||
|
glm::quat q(glm::vec3(0, 0, 1), VEC3(v));
|
||||||
|
lastack_pushquat(LS, &q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_frustumLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth) {
|
||||||
|
glm::mat4x4 mat = homogeneous_depth ?
|
||||||
|
glm::frustumLH_NO(left, right, bottom, top, near, far) :
|
||||||
|
glm::frustumLH_ZO(left, right, bottom, top, near, far);
|
||||||
|
lastack_pushmatrix(LS, &mat[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_orthoLH(struct lastack *LS, float left, float right, float bottom, float top, float near, float far, int homogeneous_depth) {
|
||||||
|
glm::mat4x4 mat = homogeneous_depth ?
|
||||||
|
glm::orthoLH_NO(left, right, bottom, top, near, far) :
|
||||||
|
glm::orthoLH_ZO(left, right, bottom, top, near, far);
|
||||||
|
lastack_pushmatrix(LS, &mat[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_base_axes(struct lastack *LS, const float forward[4]) {
|
||||||
|
glm::vec4 right, up;
|
||||||
|
|
||||||
|
if (is_equal(VEC(forward), ZAXIS)) {
|
||||||
|
up = YAXIS;
|
||||||
|
right = XAXIS;
|
||||||
|
} else {
|
||||||
|
if (is_equal(VEC(forward), YAXIS)) {
|
||||||
|
up = NZAXIS;
|
||||||
|
right = XAXIS;
|
||||||
|
} else if (is_equal(VEC(forward), NYAXIS)) {
|
||||||
|
up = ZAXIS;
|
||||||
|
right = XAXIS;
|
||||||
|
} else {
|
||||||
|
right = glm::vec4(glm::normalize(glm::cross(VEC3(&YAXIS.x), VEC3(forward))), 0);
|
||||||
|
up = glm::vec4(glm::normalize(glm::cross(VEC3(forward), VEC3(&right.x))), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastack_pushvec4(LS, &up.x);
|
||||||
|
lastack_pushvec4(LS, &right.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_quat_transform(struct lastack *LS, const float quat[4], const float v[4]){
|
||||||
|
const glm::vec4 vv = glm::rotate(QUAT(quat), VEC(v));
|
||||||
|
lastack_pushvec4(LS, &vv.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_rotmat_transform(struct lastack *LS, const float mat[16], const float v[4]){
|
||||||
|
const glm::vec4 vv = MAT(mat) * VEC(v);
|
||||||
|
lastack_pushvec4(LS, &vv.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_minmax(struct lastack *LS, const float mat[16], const float v[4], float minv[4], float maxv[4]){
|
||||||
|
const glm::vec4 vv = mat ? MAT(mat) * VEC(v) : VEC(v);
|
||||||
|
*(glm::vec4*)maxv = glm::max(vv, VEC(maxv));
|
||||||
|
*(glm::vec4*)minv = glm::min(vv, VEC(minv));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_lerp(struct lastack *LS, const float v0[4], const float v1[4], float ratio, float r[4]){
|
||||||
|
*(glm::vec4*)r = glm::lerp(VEC(v0), VEC(v1), ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
math3d_dir2radian(struct lastack *LS, const float v[4], float radians[2]){
|
||||||
|
const float PI = float(M_PI);
|
||||||
|
const float HALF_PI = 0.5f * PI;
|
||||||
|
|
||||||
|
if (is_equal(v[1], 1.f)){
|
||||||
|
radians[0] = -HALF_PI;
|
||||||
|
radians[1] = 0.f;
|
||||||
|
} else if (is_equal(v[1], -1.f)){
|
||||||
|
radians[0] = HALF_PI;
|
||||||
|
radians[1] = 0.f;
|
||||||
|
} else if (is_equal(v[0], 1.f)){
|
||||||
|
radians[0] = 0.f;
|
||||||
|
radians[1] = HALF_PI;
|
||||||
|
} else if (is_equal(v[0], -1.f)){
|
||||||
|
radians[0] = 0.f;
|
||||||
|
radians[1] = -HALF_PI;
|
||||||
|
} else if (is_equal(v[2], 1.f)){
|
||||||
|
radians[0] = 0.f;
|
||||||
|
radians[1] = 0.f;
|
||||||
|
} else if (is_equal(v[2], -1.f)){
|
||||||
|
radians[0] = 0.f;
|
||||||
|
radians[1] = PI;
|
||||||
|
} else {
|
||||||
|
radians[0] = is_zero(v[1]) ? 0.f : std::asin(-v[1]);
|
||||||
|
radians[1] = is_zero(v[0]) ? 0.f : std::atan2(v[0], v[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
#ifndef linear_algebra_refstack_h
|
||||||
|
#define linear_algebra_refstack_h
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#define MAX_REF_STACK 128
|
||||||
|
|
||||||
|
struct ref_slot {
|
||||||
|
int stack_id;
|
||||||
|
int lua_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ref_stack {
|
||||||
|
int top;
|
||||||
|
int reftop;
|
||||||
|
lua_State *L;
|
||||||
|
struct ref_slot s[MAX_REF_STACK];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_init(struct ref_stack *RS, lua_State *L) {
|
||||||
|
RS->top = 0;
|
||||||
|
RS->reftop = 0;
|
||||||
|
RS->L = L;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_push(struct ref_stack *RS) {
|
||||||
|
++RS->top;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_pop(struct ref_stack *RS) {
|
||||||
|
--RS->top;
|
||||||
|
if (RS->reftop > 0) {
|
||||||
|
if (RS->s[RS->reftop-1].stack_id == RS->top) {
|
||||||
|
--RS->reftop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_2_1(struct ref_stack *RS) {
|
||||||
|
refstack_pop(RS);
|
||||||
|
refstack_pop(RS);
|
||||||
|
refstack_push(RS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_1_1(struct ref_stack *RS) {
|
||||||
|
refstack_pop(RS);
|
||||||
|
refstack_push(RS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_pushref(struct ref_stack *RS, int lua_id) {
|
||||||
|
if (lua_id < 0) {
|
||||||
|
refstack_push(RS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (RS->reftop >= MAX_REF_STACK)
|
||||||
|
luaL_error(RS->L, "ref stack overflow");
|
||||||
|
struct ref_slot *s = &RS->s[RS->reftop++];
|
||||||
|
s->stack_id = RS->top++;
|
||||||
|
s->lua_id = lua_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
refstack_topid(struct ref_stack *RS) {
|
||||||
|
if (RS->reftop > 0) {
|
||||||
|
struct ref_slot *s = &RS->s[RS->reftop-1];
|
||||||
|
if (s->stack_id == RS->top-1) {
|
||||||
|
return s->lua_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_swap(struct ref_stack *RS) {
|
||||||
|
int top = refstack_topid(RS);
|
||||||
|
refstack_pop(RS);
|
||||||
|
int newtop = refstack_topid(RS);
|
||||||
|
refstack_pop(RS);
|
||||||
|
refstack_pushref(RS, top);
|
||||||
|
refstack_pushref(RS, newtop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
refstack_dup(struct ref_stack *RS, int index) {
|
||||||
|
int i;
|
||||||
|
int lua_id = -1;
|
||||||
|
int stack_id = RS->top - index;
|
||||||
|
for (i=RS->reftop-1;i>=0;i--) {
|
||||||
|
struct ref_slot *s = &RS->s[i];
|
||||||
|
if (s->stack_id == stack_id) {
|
||||||
|
lua_id = s->lua_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s->stack_id < stack_id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
refstack_pushref(RS, lua_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,207 @@
|
|||||||
|
local math3d = require "math3d"
|
||||||
|
|
||||||
|
local ref1 = math3d.ref()
|
||||||
|
|
||||||
|
ref1.m = {
|
||||||
|
s = 10,
|
||||||
|
r = {
|
||||||
|
axis = {1, 0, 0},
|
||||||
|
r = math.rad(60)
|
||||||
|
},
|
||||||
|
t = {1, 2, 3}
|
||||||
|
}
|
||||||
|
local ref2 = math3d.ref()
|
||||||
|
ref2.v = math3d.vector(1, 2, 3, 4)
|
||||||
|
print("ref1", ref1)
|
||||||
|
print("ref1 value", math3d.tostring(math3d.matrix(ref1)))
|
||||||
|
print(ref2)
|
||||||
|
print("ref2 value", math3d.tostring(math3d.vector(ref2)))
|
||||||
|
ref2.v = math3d.pack("dddd", 1, 2, 3, 4)
|
||||||
|
print(ref2)
|
||||||
|
ref2.v = math3d.vector(ref2, 1)
|
||||||
|
print("ref2", ref2)
|
||||||
|
|
||||||
|
for i = 1, 4 do
|
||||||
|
print("ref1 Line", i, math3d.tostring(ref1[i]))
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 4 do
|
||||||
|
print("ref2 index", i, math3d.index(ref2, i))
|
||||||
|
end
|
||||||
|
|
||||||
|
print "===SRT==="
|
||||||
|
ref1.m = {
|
||||||
|
s = 1,
|
||||||
|
r = {0, math.rad(60), 0},
|
||||||
|
t = {1, 2, 3}
|
||||||
|
}
|
||||||
|
print(ref1)
|
||||||
|
local s, r, t = math3d.srt(ref1)
|
||||||
|
print("S = ", math3d.tostring(s))
|
||||||
|
print("R = ", math3d.tostring(r))
|
||||||
|
print("T = ", math3d.tostring(t))
|
||||||
|
|
||||||
|
local function print_srt()
|
||||||
|
print("S = ", math3d.tostring(ref1.s))
|
||||||
|
print("R = ", math3d.tostring(ref1.r))
|
||||||
|
print("T = ", math3d.tostring(ref1.t))
|
||||||
|
end
|
||||||
|
|
||||||
|
print_srt()
|
||||||
|
ref1.s = 1
|
||||||
|
print_srt()
|
||||||
|
ref1.s = {3, 2, 1}
|
||||||
|
print_srt()
|
||||||
|
|
||||||
|
print "===QUAT==="
|
||||||
|
|
||||||
|
local q = math3d.quaternion {0, math.rad(60, 0), 0}
|
||||||
|
print(math3d.tostring(q))
|
||||||
|
local ref3 = math3d.ref()
|
||||||
|
ref3.m = math3d.quaternion {
|
||||||
|
axis = {1, 0, 0},
|
||||||
|
r = math.rad(60)
|
||||||
|
} -- init mat with quat
|
||||||
|
print(ref3)
|
||||||
|
ref3.q = ref3 -- convert mat to quat
|
||||||
|
print(ref3)
|
||||||
|
|
||||||
|
print "===FUNC==="
|
||||||
|
print(ref2)
|
||||||
|
ref2.v = math3d.add(ref2, ref2, ref2)
|
||||||
|
print(ref2)
|
||||||
|
ref2.v = math3d.mul(ref2, 2.5)
|
||||||
|
print("length", ref2, "=", math3d.length(ref2))
|
||||||
|
print("floor", ref2, "=", math3d.tostring(math3d.floor(ref2)))
|
||||||
|
print("dot", ref2, ref2, "=", math3d.dot(ref2, ref2))
|
||||||
|
print("cross", ref2, ref2, "=", math3d.tostring(math3d.cross(ref2, ref2)))
|
||||||
|
local point = math3d.vector(1, 2, 3, 1)
|
||||||
|
print("transformH", ref1, point, "=", math3d.tostring(math3d.transformH(ref1, point)))
|
||||||
|
print("normalize", ref2, "=", math3d.tostring(math3d.normalize(ref2)))
|
||||||
|
print("normalize", ref3, "=", math3d.tostring(math3d.normalize(ref3)))
|
||||||
|
print("transpose", ref1, "=", math3d.tostring(math3d.transpose(ref1)))
|
||||||
|
print("inverse", ref1, "=", math3d.tostring(math3d.inverse(ref1)))
|
||||||
|
print("inverse", ref2, "=", math3d.tostring(math3d.inverse(ref2)))
|
||||||
|
print("inverse", ref3, "=", math3d.tostring(math3d.inverse(ref3)))
|
||||||
|
print("reciprocal", ref2, "=", math3d.tostring(math3d.reciprocal(ref2)))
|
||||||
|
|
||||||
|
print "===MULADD==="
|
||||||
|
do
|
||||||
|
local v1, v2 = math3d.vector(1, 2, 3, 0), math3d.vector(1, 0, 0, 0)
|
||||||
|
local p = math3d.vector(4, 1, 0, 1)
|
||||||
|
local r = math3d.muladd(v1, v2, p)
|
||||||
|
print("muladd:", math3d.tostring(v1), math3d.tostring(v2), math3d.tostring(p), "=", math3d.tostring(r))
|
||||||
|
end
|
||||||
|
|
||||||
|
print "===VIEW&PROJECTION MATRIX==="
|
||||||
|
do
|
||||||
|
local eyepos = math3d.vector {0, 5, -10}
|
||||||
|
local at = math3d.vector {0, 0, 0}
|
||||||
|
local direction = math3d.normalize(math3d.vector {1, 1, 1})
|
||||||
|
local updir = math3d.vector {0, 1, 0}
|
||||||
|
|
||||||
|
local mat1 = math3d.lookat(eyepos, at, updir)
|
||||||
|
local mat2 = math3d.lookto(eyepos, direction, updir)
|
||||||
|
|
||||||
|
print("lookat matrix:", math3d.tostring(mat1), "eyepos:", math3d.tostring(eyepos), "at:", math3d.tostring(at))
|
||||||
|
|
||||||
|
print("lookto matrix:", math3d.tostring(mat2), "eyepos:", math3d.tostring(eyepos), "direction:",
|
||||||
|
math3d.tostring(direction))
|
||||||
|
|
||||||
|
local frustum = {
|
||||||
|
l = -1,
|
||||||
|
r = 1,
|
||||||
|
t = -1,
|
||||||
|
b = 1,
|
||||||
|
n = 0.1,
|
||||||
|
f = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
local perspective_mat = math3d.projmat(frustum)
|
||||||
|
|
||||||
|
local frustum_ortho = {
|
||||||
|
l = -1,
|
||||||
|
r = 1,
|
||||||
|
t = -1,
|
||||||
|
b = 1,
|
||||||
|
n = 0.1,
|
||||||
|
f = 100,
|
||||||
|
ortho = true
|
||||||
|
}
|
||||||
|
local ortho_mat = math3d.projmat(frustum_ortho)
|
||||||
|
|
||||||
|
print("perspective matrix:", math3d.tostring(perspective_mat))
|
||||||
|
print("ortho matrix:", math3d.tostring(ortho_mat))
|
||||||
|
end
|
||||||
|
|
||||||
|
print "===ROTATE VECTOR==="
|
||||||
|
do
|
||||||
|
local v = math3d.vector {1, 2, 1}
|
||||||
|
local qq = math3d.quaternion {
|
||||||
|
axis = math3d.vector {0, 1, 0},
|
||||||
|
r = math.pi * 0.5
|
||||||
|
}
|
||||||
|
local vv = math3d.transform(qq, v, 0)
|
||||||
|
print("rotate vector with quaternion", math3d.tostring(v), "=", math3d.tostring(vv))
|
||||||
|
|
||||||
|
local mat = math3d.matrix {
|
||||||
|
s = 1,
|
||||||
|
r = q,
|
||||||
|
t = math3d.vector {0, 0, 0, 1}
|
||||||
|
}
|
||||||
|
local vv2 = math3d.transform(mat, v, 0)
|
||||||
|
print("transform vector with matrix", math3d.tostring(v), "=", math3d.tostring(vv2))
|
||||||
|
|
||||||
|
local p = math3d.vector {1, 2, 1, 1}
|
||||||
|
local mat2 = math3d.matrix {
|
||||||
|
s = 1,
|
||||||
|
r = q,
|
||||||
|
t = math3d.vector {0, 0, 5, 1}
|
||||||
|
}
|
||||||
|
local r_p = math3d.transform(mat2, p, nil)
|
||||||
|
print("transform point with matrix", math3d.tostring(p), "=", math3d.tostring(r_p))
|
||||||
|
end
|
||||||
|
|
||||||
|
print "===construct coordinate from forward vector==="
|
||||||
|
do
|
||||||
|
local forward = math3d.normalize(math3d.vector {1, 1, 1})
|
||||||
|
local right, up = math3d.base_axes(forward)
|
||||||
|
print("forward:", math3d.tostring(forward), "right:", math3d.tostring(right), "up:", math3d.tostring(up))
|
||||||
|
end
|
||||||
|
|
||||||
|
print "===PROJ===="
|
||||||
|
local projmat = math3d.projmat {
|
||||||
|
fov = 90,
|
||||||
|
aspect = 1,
|
||||||
|
n = 1,
|
||||||
|
f = 1000
|
||||||
|
}
|
||||||
|
print("PROJ", math3d.tostring(projmat))
|
||||||
|
|
||||||
|
print "===ADAPTER==="
|
||||||
|
local adapter = require "math3d.adapter"
|
||||||
|
local testfunc = require "math3d.adapter.test"
|
||||||
|
|
||||||
|
local vector = adapter.vector(testfunc.vector, 1) -- convert arguments to vector pointer from 1
|
||||||
|
local matrix1 = adapter.matrix(testfunc.matrix1, 1, 1) -- convert 1 mat
|
||||||
|
local matrix2 = adapter.matrix(testfunc.matrix2, 1, 2) -- convert 2 mat
|
||||||
|
local matrix = adapter.matrix(testfunc.matrix2, 1) -- convert all mat
|
||||||
|
local var = adapter.variant(testfunc.vector, testfunc.matrix1, 1)
|
||||||
|
local format = adapter.format(testfunc.variant, testfunc.format, 2)
|
||||||
|
local mvq = adapter.getter(testfunc.getmvq, "mvq") -- getmvq will return matrix, vector, quat
|
||||||
|
local matrix2_v = adapter.format(testfunc.matrix2, "mm", 1)
|
||||||
|
local retvec = adapter.output_vector(testfunc.retvec, 1)
|
||||||
|
print(vector(ref2, math3d.vector {1, 2, 3}))
|
||||||
|
print(matrix1(ref1))
|
||||||
|
print(matrix2(ref1, ref1))
|
||||||
|
print(matrix2_v(ref1, ref1))
|
||||||
|
print(matrix(ref1, ref1))
|
||||||
|
print(var(ref1))
|
||||||
|
print(var(ref2))
|
||||||
|
print(format("mv", ref1, ref2))
|
||||||
|
local m, v, qv = mvq()
|
||||||
|
print(math3d.tostring(m), math3d.tostring(v), math3d.tostring(qv))
|
||||||
|
|
||||||
|
local v1, v2 = retvec()
|
||||||
|
print(math3d.tostring(v1), math3d.tostring(v2))
|
||||||
|
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
#define LUA_LIB
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
lvector(lua_State *L) {
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
int i,j;
|
||||||
|
luaL_checkstack(L, top * 4+1, NULL);
|
||||||
|
lua_pushstring(L, "VEC");
|
||||||
|
for (i=1;i<=top;i++) {
|
||||||
|
const float * vec4 = lua_touserdata(L, i);
|
||||||
|
for (j=0;j<4;j++) {
|
||||||
|
lua_pushnumber(L, vec4[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 4 * top + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lmatrix1(lua_State *L) {
|
||||||
|
int i;
|
||||||
|
const float * mat = lua_touserdata(L, 1);
|
||||||
|
lua_pushstring(L, "MAT");
|
||||||
|
for (i=0;i<16;i++) {
|
||||||
|
lua_pushnumber(L, mat[i]);
|
||||||
|
}
|
||||||
|
return 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lmatrix2(lua_State *L) {
|
||||||
|
int i;
|
||||||
|
const float * mat1 = lua_touserdata(L, 1);
|
||||||
|
const float * mat2 = lua_touserdata(L, 2);
|
||||||
|
for (i=0;i<16;i++) {
|
||||||
|
lua_pushnumber(L, mat1[i] - mat2[i]);
|
||||||
|
}
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lformat(lua_State *L) {
|
||||||
|
const char * format = lua_tostring(L, 1);
|
||||||
|
lua_pushlightuserdata(L, (void *)format);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lvariant(lua_State *L) {
|
||||||
|
size_t sz;
|
||||||
|
const char * format = lua_tolstring(L, 1, &sz);
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
if (sz+1 != top) {
|
||||||
|
return luaL_error(L, "%s need %d arguments", format, (int)sz);
|
||||||
|
}
|
||||||
|
luaL_checkstack(L, sz, NULL);
|
||||||
|
int i;
|
||||||
|
for (i=2;i<=top;i++) {
|
||||||
|
const float * v = (const float *)lua_touserdata(L, i);
|
||||||
|
switch(format[i-2]) {
|
||||||
|
case 'm':
|
||||||
|
lua_pushnumber(L, v[15]);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
lua_pushnumber(L, v[0]);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
lua_pushnumber(L, v[3]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return luaL_error(L, "Invalid format %s", format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lgetmvq(lua_State *L) {
|
||||||
|
float * mat = lua_touserdata(L, 1);
|
||||||
|
float * vec = lua_touserdata(L, 2);
|
||||||
|
float * quat = lua_touserdata(L, 3);
|
||||||
|
int i;
|
||||||
|
for (i=0;i<16;i++) {
|
||||||
|
mat[i] = (float)i;
|
||||||
|
}
|
||||||
|
for (i=0;i<4;i++) {
|
||||||
|
vec[i] = (float)i;
|
||||||
|
}
|
||||||
|
for (i=0;i<4;i++) {
|
||||||
|
quat[i] = 1.0f;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lretvector(lua_State *L) {
|
||||||
|
static const float v1[4] = { 1.0f, 2.0f, 3.0f, 4.0f };
|
||||||
|
static const float v2[4] = { 5.0f, 6.0f, 7.0f, 8.0f };
|
||||||
|
lua_pushlightuserdata(L, (void *)v1);
|
||||||
|
lua_pushlightuserdata(L, (void *)v2);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
LUAMOD_API int
|
||||||
|
luaopen_math3d_adapter_test(lua_State *L) {
|
||||||
|
luaL_checkversion(L);
|
||||||
|
luaL_Reg l[] = {
|
||||||
|
{ "vector", lvector },
|
||||||
|
{ "matrix1", lmatrix1 },
|
||||||
|
{ "matrix2", lmatrix2 },
|
||||||
|
{ "format", lformat },
|
||||||
|
{ "variant", lvariant },
|
||||||
|
{ "getmvq", lgetmvq },
|
||||||
|
{ "retvec", lretvector },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
luaL_newlib(L, l);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef math3d_util_h
|
||||||
|
#define math3d_util_h
|
||||||
|
|
||||||
|
#include "glm/glm.hpp"
|
||||||
|
#include "glm/gtc/constants.hpp"
|
||||||
|
#include "glm/ext/scalar_constants.hpp"
|
||||||
|
#include "glm/ext/scalar_relational.hpp"
|
||||||
|
#include "glm/ext/vector_relational.hpp"
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool
|
||||||
|
is_zero(const T& a, const T& e = T(glm::epsilon<float>())) {
|
||||||
|
return glm::all(glm::equal(a, glm::zero<T>(), e));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
is_zero(const float& a, float e = glm::epsilon<float>()) {
|
||||||
|
return glm::equal(a, glm::zero<float>(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool
|
||||||
|
is_equal(const T& a, const T& b, const T& e = T(glm::epsilon<float>())) {
|
||||||
|
return is_zero(a - b, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //math3d_util_h
|
||||||
Loading…
Reference in New Issue