Compare commits

..

No commits in common. 'develop' and 'master' have entirely different histories.

1
.gitignore vendored

@ -3,7 +3,6 @@
*.pid
*.o
*.so
*.a
*.lib
*.tar.gz
*.log

18
.gitmodules vendored

@ -1,15 +1,3 @@
[submodule "code/framework/3rd/ffi-lua"]
path = code/framework/3rd/ffi-lua
url = git@github.com:cloudfreexiao/cffi-lua.git
[submodule "code/framework/3rd/glm"]
path = code/framework/3rd/glm
url = git@github.com:g-truc/glm.git
[submodule "code/framework/3rd/termbox"]
path = code/framework/3rd/termbox
url = git@github.com:nullgemm/termbox_next.git
[submodule "code/framework/skynet"]
path = code/framework/skynet
url = git@github.com:cloudfreexiao/skynet.git
[submodule "code/goscon"]
path = code/goscon
url = git@github.com:cloudfreexiao/goscon.git
[submodule "framework/skynet"]
path = framework/skynet
url = https://github.com/cloudfreexiao/skynet.git

@ -12,16 +12,9 @@ exclude_files = {
globals = {
"SERVICE_NAME",
"class",
"singleton",
"instanceof",
"mixin",
"Handler",
"Fmt",
"Property",
"Enum",
"Option",
"Try",
"ZLog",
"handler",
"gLog",
"gEnv",
}
ignore = {

@ -1 +0,0 @@
Subproject commit 5cebc788e09a6b9ffb61bd72db9e2bde6c5ff6ce

@ -1 +0,0 @@
Subproject commit 06ed280db4e274fa5e1f36d5ea4f7dfd654ff9b0

@ -1,14 +0,0 @@
Makefile.in
autom4te.cache/*
aclocal.m4
config.guess
config.sub
configure
depcomp
install-sh
ltmain.sh
missing
*~
src/gjk/config.h.in
build/*
ccd.pc

@ -1,23 +0,0 @@
dist: trusty
sudo: required
language: c
compiler:
- gcc
- clang
env:
global:
- PREFIX="$TRAVIS_BUILD_DIR/build/install"
matrix:
- USE_AUTOTOOLS=yes
- USE_CMAKE=yes
- USE_MAKEFILE=yes USE_DOUBLE=yes
- USE_MAKEFILE=yes USE_SINGLE=yes
script:
- mkdir -p "$PREFIX"
- if [[ "$USE_AUTOTOOLS" == "yes" ]]; then ./bootstrap && cd build && ../configure --prefix "$PREFIX"; fi
- if [[ "$USE_CMAKE" == "yes" ]]; then cd build && cmake "-DCMAKE_INSTALL_PREFIX=$PREFIX" ..; fi
- if [[ "$USE_MAKEFILE" == "yes" ]]; then cd src; fi
- make && make install

@ -1,75 +0,0 @@
cmake_minimum_required(VERSION 2.8.11)
if(POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif()
# Can not explicitly declared the software as C in project command due to bug:
# https://gitlab.kitware.com/cmake/cmake/issues/16967
project(libccd)
set(CCD_VERSION_MAJOR 2)
set(CCD_VERSION_MINOR 0)
set(CCD_VERSION ${CCD_VERSION_MAJOR}.${CCD_VERSION_MINOR})
set(CCD_SOVERSION 2)
# Include GNUInstallDirs to get canonical paths
include(GNUInstallDirs)
include(CTest)
option(BUILD_DOCUMENTATION "Build the documentation" OFF)
option(BUILD_SHARED_LIBS "Build libccd as a shared library" ON)
option(ENABLE_DOUBLE_PRECISION
"Enable double precision computations instead of single precision" OFF)
# Option for some bundle-like build system in order not to expose
# any FCL binary symbols in their public ABI
option(CCD_HIDE_ALL_SYMBOLS "Hide all binary symbols" OFF)
if (CCD_HIDE_ALL_SYMBOLS)
add_definitions("-DCCD_STATIC_DEFINE")
endif()
# set the default build type
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build; options are Debug Release RelWithDebInfo MinSizeRel"
FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS
Debug
Release
RelWithDebInfo
MinSizeRel)
endif()
add_subdirectory(src)
if(BUILD_DOCUMENTATION)
add_subdirectory(doc)
endif()
include(CMakePackageConfigHelpers)
configure_package_config_file(ccd-config.cmake.in ccd-config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/ccd"
PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
write_basic_package_version_file(ccd-config-version.cmake
VERSION ${CCD_VERSION} COMPATIBILITY AnyNewerVersion)
install(FILES
"${CMAKE_BINARY_DIR}/ccd-config.cmake"
"${CMAKE_BINARY_DIR}/ccd-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/ccd")
set(CCD_PKGCONFIG_DESCRIPTION
"Library for collision detection between convex shapes")
configure_file(ccd.pc.in ccd.pc @ONLY)
install(FILES "${CMAKE_BINARY_DIR}/ccd.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
install(FILES BSD-LICENSE DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/ccd")

@ -1,6 +0,0 @@
SUBDIRS = src
EXTRA_DIST = doc \
BSD-LICENSE \
README.md \
make-release.sh

@ -1,296 +0,0 @@
# libccd [![Build Status](https://travis-ci.org/danfis/libccd.svg?branch=master)](https://travis-ci.org/danfis/libccd)
***libccd*** is library for a collision detection between two convex shapes.
libccd implements variation on GilbertJohnsonKeerthi algorithm plus Expand
Polytope Algorithm (EPA) and also implements algorithm Minkowski Portal
Refinement (MPR, a.k.a. XenoCollide) as described in Game Programming Gems 7.
libccd is the only available open source library of my knowledge that include
MPR algorithm working in 3-D space. However, there is a library called
[mpr2d](http://code.google.com/p/mpr2d/), implemented in D programming
language, that works in 2-D space.
libccd is currently part of:
1. [ODE](http://www.ode.org/) library (see ODE's *./configure --help* how to enable it),
2. [FCL](http://www.ros.org/wiki/fcl) library from [Willow Garage](http://www.willowgarage.com/),
3. [Bullet3](http://bulletphysics.org/) library (https://github.com/bulletphysics/bullet3).
For implementation details on GJK algorithm, see
http://www.win.tue.nl/~gino/solid/jgt98convex.pdf.
## Dependencies
This library is currently based only on standard libraries.
The only exception are testsuites that are built on top of CU
(https://github.com/danfis/cu) library licensed under LGPL, however only
testing depends on it and libccd library itself can be distributed without it.
## License
libccd is licensed under OSI-approved 3-clause BSD License, text of license
is distributed along with source code in BSD-LICENSE file.
Each file should include license notice, the rest should be considered as
licensed under 3-clause BSD License.
## Compile And Install
libccd contains several mechanisms for compiling and installing. Using a simple Makefile, using autotools, and using CMake.
### 1. Using Makefile
Directory src/ contains Makefile that should contain everything needed for compilation and installation:
```sh
$ cd src/
$ make
$ make install
```
Library libccd is by default compiled in double precision of floating point numbers - you can change this by options *USE_SINGLE/USE_DOUBLE*, i.e.:
```sh
$ make USE_SINGLE=yes
```
will compile library in single precision.
Installation directory can be changed by options PREFIX, INCLUDEDIR and LIBDIR.
For more info type 'make help'.
### 2. Using Autotools
libccd also contains support for autotools:
Generate configure script etc.:
```sh
$ ./bootstrap
```
Create new build/ directory:
```sh
$ mkdir build && cd build
```
Run configure script:
```sh
$ ../configure
```
Run make and make install:
```sh
$ make && make install
```
configure script can change the way libccd is compiled and installed, most significant option is *--enable-double-precision* which enables double precision (single is default in this case).
### 3. Using CMake
To build using `make`:
```sh
$ mkdir build && cd build
$ cmake -G "Unix Makefiles" ..
$ make && make install
```
To build using `ninja`:
```sh
$ mkdir build && cd build
$ cmake -G Ninja ..
$ ninja && ninja install
```
Other build tools may be using by specifying a different generator. For example:
```sh
$ cmake -G Xcode ..
```
```bat
> cmake -G "Visual Studio 14 2015" ..
```
To compile using double precision, set the `ENABLE_DOUBLE_PRECISION` option:
```sh
$ mkdir build && cd build
$ cmake -G "Unix Makefiles" -DENABLE_DOUBLE_PRECISION=ON ..
$ make && make install
```
To build libccd as a shared library, set the `BUILD_SHARED_LIBS` option:
```sh
$ mkdir build && cd build
$ cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=ON ..
$ make && make install
```
To build the test suite, set the `BUILD_TESTING` option:
```sh
$ mkdir build && cd build
$ cmake -G "Unix Makefiles" -DBUILD_TESTING=ON ..
$ make && make test
```
The installation directory may be changed using the `CMAKE_INSTALL_PREFIX` variable:
```sh
$ mkdir build && cd build
$ cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/path/to/install ..
$ make && make install
```
## GJK - Intersection Test
This section describes how to use libccd for testing if two convex objects intersects (i.e., 'yes/no' test) using Gilbert-Johnson-Keerthi (GJK) algorithm.
Procedure is very simple (and is similar for usages of library):
1. Include *<ccd/ccd.h>* file.
2. Implement support function for specific shapes. Support function is function that returns furthest point from object (shape) in specified direction.
3. Set up *ccd_t* structure.
4. Run ccdGJKIntersect() function on desired objects.
Here is skeleton of simple program:
```cpp
#include <ccd/ccd.h>
#include <ccd/quat.h> // for work with quaternions
/** Support function for box */
void support(const void *obj, const ccd_vec3_t *dir, ccd_vec3_t *vec)
{
// assume that obj_t is user-defined structure that holds info about
// object (in this case box: x, y, z, pos, quat - dimensions of box,
// position and rotation)
obj_t *obj = (obj_t *)_obj;
ccd_vec3_t dir;
ccd_quat_t qinv;
// apply rotation on direction vector
ccdVec3Copy(&dir, _dir);
ccdQuatInvert2(&qinv, &obj->quat);
ccdQuatRotVec(&dir, &qinv);
// compute support point in specified direction
ccdVec3Set(v, ccdSign(ccdVec3X(&dir)) * box->x * CCD_REAL(0.5),
ccdSign(ccdVec3Y(&dir)) * box->y * CCD_REAL(0.5),
ccdSign(ccdVec3Z(&dir)) * box->z * CCD_REAL(0.5));
// transform support point according to position and rotation of object
ccdQuatRotVec(v, &obj->quat);
ccdVec3Add(v, &obj->pos);
}
int main(int argc, char *argv[])
{
...
ccd_t ccd;
CCD_INIT(&ccd); // initialize ccd_t struct
// set up ccd_t struct
ccd.support1 = support; // support function for first object
ccd.support2 = support; // support function for second object
ccd.max_iterations = 100; // maximal number of iterations
int intersect = ccdGJKIntersect(obj1, obj2, &ccd);
// now intersect holds true if obj1 and obj2 intersect, false otherwise
}
```
## GJK + EPA - Penetration Of Two Objects
If you want to obtain also penetration info about two intersection objects ccdGJKPenetration() function can be used.
Procedure is almost same as for previous case:
```cpp
#include <ccd/ccd.h>
#include <ccd/quat.h> // for work with quaternions
/** Support function is same as in previous case */
int main(int argc, char *argv[])
{
...
ccd_t ccd;
CCD_INIT(&ccd); // initialize ccd_t struct
// set up ccd_t struct
ccd.support1 = support; // support function for first object
ccd.support2 = support; // support function for second object
ccd.max_iterations = 100; // maximal number of iterations
ccd.epa_tolerance = 0.0001; // maximal tolerance fro EPA part
ccd_real_t depth;
ccd_vec3_t dir, pos;
int intersect = ccdGJKPenetration(obj1, obj2, &ccd, &depth, &dir, &pos);
// now intersect holds 0 if obj1 and obj2 intersect, -1 otherwise
// in depth, dir and pos is stored penetration depth, direction of
// separation vector and position in global coordinate system
}
```
## MPR - Intersection Test
libccd also provides MPR - Minkowski Portal Refinement algorithm that can be used for testing if two objects intersects.
Procedure is similar to the one used for GJK algorithm. Support function is same but also function that returns center (or any point near center) of given object must be implemented:
```cpp
#include <ccd/ccd.h>
#include <ccd/quat.h> // for work with quaternions
/** Support function is same as in previous case */
/** Center function - returns center of object */
void center(const void *_obj, ccd_vec3_t *center)
{
obj_t *obj = (obj_t *)_obj;
ccdVec3Copy(center, &obj->pos);
}
int main(int argc, char *argv[])
{
...
ccd_t ccd;
CCD_INIT(&ccd); // initialize ccd_t struct
// set up ccd_t struct
ccd.support1 = support; // support function for first object
ccd.support2 = support; // support function for second object
ccd.center1 = center; // center function for first object
ccd.center2 = center; // center function for second object
ccd.mpr_tolerance = 0.0001; // maximal tolerance
int intersect = ccdMPRIntersect(obj1, obj2, &ccd);
// now intersect holds true if obj1 and obj2 intersect, false otherwise
}
```
## MPR - Penetration Of Two Objects
Using MPR algorithm for obtaining penetration info about two intersection objects is equally easy as in previous case instead ccdMPRPenetration() function is used:
```cpp
#include <ccd/ccd.h>
#include <ccd/quat.h> // for work with quaternions
/** Support function is same as in previous case */
/** Center function is same as in prevous case */
int main(int argc, char *argv[])
{
...
ccd_t ccd;
CCD_INIT(&ccd); // initialize ccd_t struct
// set up ccd_t struct
ccd.support1 = support; // support function for first object
ccd.support2 = support; // support function for second object
ccd.center1 = center; // center function for first object
ccd.center2 = center; // center function for second object
ccd.mpr_tolerance = 0.0001; // maximal tolerance
ccd_real_t depth;
ccd_vec3_t dir, pos;
int intersect = ccdMPRPenetration(obj1, obj2, &ccd, &depth, &dir, &pos);
// now intersect holds 0 if obj1 and obj2 intersect, -1 otherwise
// in depth, dir and pos is stored penetration depth, direction of
// separation vector and position in global coordinate system
}
```

@ -1,7 +0,0 @@
#!/bin/sh
libtoolize -f -c
aclocal
autoheader -f
autoconf
automake -a --foreign -f -c

@ -1,14 +0,0 @@
@PACKAGE_INIT@
set(CCD_VERSION_MAJOR @CCD_VERSION_MAJOR@)
set(CCD_VERSION_MINOR @CCD_VERSION_MINOR@)
set(CCD_VERSION @CCD_VERSION@)
set(CCD_SOVERSION @CCD_SOVERSION@)
set(CCD_FOUND ON)
set_and_check(CCD_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
set_and_check(CCD_LIBRARY_DIRS "@PACKAGE_CMAKE_INSTALL_LIBDIR@")
set(CCD_LIBRARIES ccd)
include("${CMAKE_CURRENT_LIST_DIR}/ccd-targets.cmake")

@ -1,13 +0,0 @@
# Generated by CMake @CMAKE_VERSION@ for ccd
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: @CCD_PKGCONFIG_DESCRIPTION@
Version: @CCD_VERSION@
Requires: @CCD_PKGCONFIG_REQUIRES@
Libs: -L${libdir} -lccd @CCD_PKGCONFIG_EXTRA_LIBS@
Cflags: -I${includedir}

@ -1,50 +0,0 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
#AC_PREREQ([2.65])
AC_INIT([libccd], [2.0], [danfis@danfis.cz])
AC_CONFIG_SRCDIR([src/ccd.c])
AC_CONFIG_HEADERS([src/ccd/config.h])
AM_INIT_AUTOMAKE
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AC_PROG_INSTALL
AC_DISABLE_SHARED
LT_INIT
# Checks for libraries.
AC_CHECK_LIB([m], [main])
# FIXME: Replace `main' with a function in `-lrt':
AC_CHECK_LIB([rt], [main])
# Checks for header files.
AC_CHECK_HEADERS([float.h stdlib.h string.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_REALLOC
AC_CHECK_FUNCS([clock_gettime])
use_double=no
AC_ARG_ENABLE(double-precision,
AS_HELP_STRING([--enable-double-precision],
[enable double precision computations instead of single precision]),
[use_double=yes])
if test $use_double = no
then
AC_DEFINE([CCD_SINGLE], [], [use single precision])
else
AC_DEFINE([CCD_DOUBLE], [], [use double precision])
fi
AC_CONFIG_FILES([Makefile
src/Makefile
src/testsuites/Makefile
src/testsuites/cu/Makefile])
AC_OUTPUT

@ -1,31 +0,0 @@
#!/bin/bash
# Creates .tar.gz package of specified version.
# Takes one argument - identification of commit
NAME=libccd
COMMIT=""
CMD="git archive"
# read arguments
COMMIT="$1"
if [ "$COMMIT" = "" ]; then
echo "Usage: $0 commit [--notest] [--nodoc]"
echo "Error: you must specify commit which should be packed"
exit -1;
fi;
PREFIX=${NAME}-$COMMIT/
FN=${NAME}-$COMMIT.tar.gz
if echo "$COMMIT" | grep '^v[0-9]\.[0-9]\+' >/dev/null 2>&1; then
tmp=$(echo "$COMMIT" | sed 's/^v//')
PREFIX=${NAME}-$tmp/
FN=${NAME}-$tmp.tar.gz
fi
$CMD --prefix="$PREFIX" --format=tar $COMMIT | gzip >"$FN"
echo "Package: $FN"

@ -1,5 +0,0 @@
*.o
*.a
ccd/config.h
ccd/config.h.in

@ -1,88 +0,0 @@
if(DEFINED CCD_SINGLE OR DEFINED CCD_DOUBLE)
# make sure only DOUBLE or SINGLE is set; default to SINGLE
if(CCD_SINGLE)
set(CCD_DOUBLE OFF)
else()
set(CCD_SINGLE ON)
endif()
if(CCD_DOUBLE)
set(CCD_SINGLE OFF)
endif()
elseif(ENABLE_DOUBLE_PRECISION)
set(CCD_DOUBLE ON)
set(CCD_SINGLE OFF)
else()
set(CCD_DOUBLE OFF)
set(CCD_SINGLE ON)
endif()
configure_file(ccd/config.h.cmake.in ccd/config.h)
set(CCD_INCLUDES
ccd/ccd.h
ccd/compiler.h
ccd/ccd_export.h
ccd/quat.h
ccd/vec3.h
"${CMAKE_CURRENT_BINARY_DIR}/ccd/config.h")
set(CCD_SOURCES
alloc.h
ccd.c
dbg.h
list.h
mpr.c
polytope.c
polytope.h
simplex.h
support.c
support.h
vec3.c)
add_library(ccd ${CCD_INCLUDES} ${CCD_SOURCES})
set_target_properties(ccd PROPERTIES
PUBLIC_HEADER "${CCD_INCLUDES}"
SOVERSION ${CCD_SOVERSION}
VERSION ${CCD_VERSION})
target_include_directories(ccd PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
if(NOT WIN32)
find_library(LIBM_LIBRARY NAMES m)
if(NOT LIBM_LIBRARY)
message(FATAL_ERROR "Could NOT find required library LibM")
endif()
target_link_libraries(ccd "${LIBM_LIBRARY}")
if(BUILD_SHARED_LIBS)
set(CCD_PKGCONFIG_EXTRA_LIBS -lm PARENT_SCOPE)
endif()
endif()
export(TARGETS ccd FILE "${CMAKE_BINARY_DIR}/ccd-targets.cmake")
install(TARGETS ccd
EXPORT ccd-targets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ccd"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(EXPORT ccd-targets DESTINATION "${CMAKE_INSTALL_LIBDIR}/ccd")
macro (check_compiler_visibility)
include (CheckCXXCompilerFlag)
check_cxx_compiler_flag(-fvisibility=hidden COMPILER_SUPPORTS_VISIBILITY)
endmacro()
if(UNIX)
check_compiler_visibility()
if (COMPILER_SUPPORTS_VISIBILITY)
set_target_properties(ccd
PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
endif()
endif()
if(NOT WIN32 AND BUILD_TESTING AND NOT CCD_HIDE_ALL_SYMBOLS)
add_subdirectory(testsuites)
endif()

@ -1,80 +0,0 @@
###
# libccd
# ---------------------------------
# Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
#
#
# This file is part of libccd.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file BDS-LICENSE for details or see
# <http://www.opensource.org/licenses/bsd-license.php>.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
##
-include Makefile.include
CFLAGS += -I. -fvisibility=hidden
TARGETS = libccd.a
OBJS = ccd.o mpr.o support.o vec3.o polytope.o
all: $(TARGETS)
libccd.a: $(OBJS)
ar cr $@ $(OBJS)
ranlib $@
ccd/config.h: ccd/config.h.m4
$(M4) $(CONFIG_FLAGS) $< >$@
%.o: %.c %.h ccd/config.h
$(CC) $(CFLAGS) $(DEFS) -c -o $@ $<
%.o: %.c ccd/config.h
$(CC) $(CFLAGS) $(DEFS) -c -o $@ $<
%.h: ccd/config.h
%.c: ccd/config.h
install:
mkdir -p $(PREFIX)/$(INCLUDEDIR)/ccd
mkdir -p $(PREFIX)/$(LIBDIR)
cp ccd/*.h $(PREFIX)/$(INCLUDEDIR)/ccd/
cp libccd.a $(PREFIX)/$(LIBDIR)
clean:
rm -f $(OBJS)
rm -f $(TARGETS)
rm -f ccd/config.h
if [ -d testsuites ]; then $(MAKE) -C testsuites clean; fi;
check:
$(MAKE) -C testsuites check
check-valgrind:
$(MAKE) -C testsuites check-valgrind
help:
@echo "Targets:"
@echo " all - Build library"
@echo " install - Install library into system"
@echo ""
@echo "Options:"
@echo " CC - Path to C compiler"
@echo " M4 - Path to m4 macro processor"
@echo ""
@echo " DEBUG 'yes'/'no' - Turn on/off debugging (default: 'no')"
@echo " PROFIL 'yes'/'no' - Compiles profiling info (default: 'no')"
@echo " NOWALL 'yes'/'no' - Turns off -Wall gcc option (default: 'no')"
@echo " NOPEDANTIC 'yes'/'no' - Turns off -pedantic gcc option (default: 'no')"
@echo ""
@echo " USE_SINGLE 'yes' - Use single precision (default: 'no')"
@echo " USE_DOUBLE 'yes' - Use double precision (default: 'yes')"
@echo ""
@echo " PREFIX - Prefix where library will be installed (default: /usr/local)"
@echo " INCLUDEDIR - Directory where header files will be installed (PREFIX/INCLUDEDIR) (default: include)"
@echo " LIBDIR - Directory where library will be installed (PREFIX/LIBDIR) (default: lib)"
@echo ""
.PHONY: all clean check check-valgrind help

@ -1,18 +0,0 @@
SUBDIRS = . testsuites
lib_LTLIBRARIES = libccd.la
libccd_la_SOURCES = alloc.h \
ccd/compiler.h \
dbg.h \
ccd.c ccd/ccd.h \
ccd/ccd_export.h \
list.h \
polytope.c polytope.h \
ccd/quat.h \
simplex.h \
support.c support.h \
vec3.c ccd/vec3.h \
mpr.c
libccd_la_CFLAGS = -fvisibility=hidden

@ -1,100 +0,0 @@
###
# libccd
# ---------------------------------
# Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
#
#
# This file is part of libccd.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file BDS-LICENSE for details or see
# <http://www.opensource.org/licenses/bsd-license.php>.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
##
CC ?= gcc
M4 ?= m4
PYTHON ?= python
SYSTEM = $(shell uname)
SYSTEM_CXXFLAGS =
SYSTEM_LDFLAGS =
ifeq '$(SYSTEM)' 'FreeBSD'
SYSTEM_CXXFLAGS = -Wno-long-long
else
endif
NOWALL ?= no
NOPEDANTIC ?= no
DEBUG ?= no
PROFIL ?= no
ifeq '$(PROFIL)' 'yes'
DEBUG = yes
endif
ifeq '$(DEBUG)' 'yes'
CFLAGS = -g
endif
ifeq '$(PROFIL)' 'yes'
CFLAGS += -pg
endif
ifneq '$(NOWALL)' 'yes'
CFLAGS += -Wall
endif
ifneq '$(NOPEDANTIC)' 'yes'
CFLAGS += -pedantic
endif
CONFIG_FLAGS =
USE_DOUBLE ?= yes
USE_SINGLE ?= no
ifeq '$(USE_SINGLE)' 'yes'
CONFIG_FLAGS += -DUSE_SINGLE
USE_DOUBLE = no
endif
ifeq '$(USE_DOUBLE)' 'yes'
CONFIG_FLAGS += -DUSE_DOUBLE
endif
CFLAGS += --std=gnu99
LDFLAGS += $(SYSTEM_LDFLAGS)
CHECKTARGETS =
check-dep: $(CHECKTARGETS)
PREFIX ?= /usr/local
INCLUDEDIR ?= include
LIBDIR ?= lib
showvars:
@echo "SYSTEM = "$(SYSTEM)
@echo ""
@echo "CC = $(CC)"
@echo "M4 = $(M4)"
@echo ""
@echo "DEBUG = $(DEBUG)"
@echo "PROFIL = $(PROFIL)"
@echo "NOWALL = $(NOWALL)"
@echo "NOPEDANTIC = $(NOPEDANTIC)"
@echo "USE_SINGLE = $(USE_SINGLE)"
@echo "USE_DOUBLE = $(USE_DOUBLE)"
@echo ""
@echo "CFLAGS = $(CFLAGS)"
@echo "LDFLAGS = $(LDFLAGS)"
@echo "CONFIG_FLAGS = $(CONFIG_FLAGS)"
@echo ""
@echo "PREFIX = $(PREFIX)"
@echo "INCLUDEDIR = $(INCLUDEDIR)"
@echo "LIBDIR = $(LIBDIR)"
@echo ""
.DEFAULT_GOAL := all
.PHONY: showvars

@ -1,50 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_ALLOC_H__
#define __CCD_ALLOC_H__
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Functions and macros required for memory allocation.
*/
/* Memory allocation: */
#define __CCD_ALLOC_MEMORY(type, ptr_old, size) \
(type *)realloc((void *)ptr_old, (size))
/** Allocate memory for one element of type. */
#define CCD_ALLOC(type) \
__CCD_ALLOC_MEMORY(type, NULL, sizeof(type))
/** Allocate memory for array of elements of type type. */
#define CCD_ALLOC_ARR(type, num_elements) \
__CCD_ALLOC_MEMORY(type, NULL, sizeof(type) * (num_elements))
#define CCD_REALLOC_ARR(ptr, type, num_elements) \
__CCD_ALLOC_MEMORY(type, ptr, sizeof(type) * (num_elements))
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_ALLOC_H__ */

@ -1,996 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2012 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#include <stdio.h>
#include <float.h>
#include <ccd/ccd.h>
#include <ccd/vec3.h>
#include "simplex.h"
#include "polytope.h"
#include "alloc.h"
#include "dbg.h"
/** Performs GJK algorithm. Returns 0 if intersection was found and simplex
* is filled with resulting polytope. */
static int __ccdGJK(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_simplex_t *simplex);
/** Performs GJK+EPA algorithm. Returns 0 if intersection was found and
* pt is filled with resulting polytope and nearest with pointer to
* nearest element (vertex, edge, face) of polytope to origin. */
static int __ccdGJKEPA(const void *obj1, const void *obj2,
const ccd_t *ccd,
ccd_pt_t *pt, ccd_pt_el_t **nearest);
/** Returns true if simplex contains origin.
* This function also alteres simplex and dir according to further
* processing of GJK algorithm. */
static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir);
static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir);
static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir);
static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir);
/** d = a x b x c */
_ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b,
const ccd_vec3_t *c, ccd_vec3_t *d);
/** Transforms simplex to polytope. It is assumed that simplex has 4
* vertices. */
static int simplexToPolytope4(const void *obj1, const void *obj2,
const ccd_t *ccd,
ccd_simplex_t *simplex,
ccd_pt_t *pt, ccd_pt_el_t **nearest);
/** Transforms simplex to polytope, three vertices required */
static int simplexToPolytope3(const void *obj1, const void *obj2,
const ccd_t *ccd,
const ccd_simplex_t *simplex,
ccd_pt_t *pt, ccd_pt_el_t **nearest);
/** Transforms simplex to polytope, two vertices required */
static int simplexToPolytope2(const void *obj1, const void *obj2,
const ccd_t *ccd,
const ccd_simplex_t *simplex,
ccd_pt_t *pt, ccd_pt_el_t **nearest);
/** Expands polytope using new vertex v.
* Return 0 on success, -2 on memory allocation failure.*/
static int expandPolytope(ccd_pt_t *pt, ccd_pt_el_t *el,
const ccd_support_t *newv);
/** Finds next support point (at stores it in out argument).
* Returns 0 on success, -1 otherwise */
static int nextSupport(const void *obj1, const void *obj2, const ccd_t *ccd,
const ccd_pt_el_t *el,
ccd_support_t *out);
void ccdFirstDirDefault(const void *o1, const void *o2, ccd_vec3_t *dir)
{
ccdVec3Set(dir, CCD_ONE, CCD_ZERO, CCD_ZERO);
}
int ccdGJKIntersect(const void *obj1, const void *obj2, const ccd_t *ccd)
{
ccd_simplex_t simplex;
return __ccdGJK(obj1, obj2, ccd, &simplex) == 0;
}
int ccdGJKSeparate(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_vec3_t *sep)
{
ccd_pt_t polytope;
ccd_pt_el_t *nearest;
int ret;
ccdPtInit(&polytope);
ret = __ccdGJKEPA(obj1, obj2, ccd, &polytope, &nearest);
// set separation vector
if (nearest)
ccdVec3Copy(sep, &nearest->witness);
ccdPtDestroy(&polytope);
return ret;
}
static int penEPAPosCmp(const void *a, const void *b)
{
ccd_pt_vertex_t *v1, *v2;
v1 = *(ccd_pt_vertex_t **)a;
v2 = *(ccd_pt_vertex_t **)b;
if (ccdEq(v1->dist, v2->dist)){
return 0;
}else if (v1->dist < v2->dist){
return -1;
}else{
return 1;
}
}
static int penEPAPos(const ccd_pt_t *pt, const ccd_pt_el_t *nearest,
ccd_vec3_t *pos)
{
ccd_pt_vertex_t *v;
ccd_pt_vertex_t **vs;
size_t i, len;
ccd_real_t scale;
// compute median
len = 0;
ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){
len++;
}
vs = CCD_ALLOC_ARR(ccd_pt_vertex_t *, len);
if (vs == NULL)
return -1;
i = 0;
ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){
vs[i++] = v;
}
qsort(vs, len, sizeof(ccd_pt_vertex_t *), penEPAPosCmp);
ccdVec3Set(pos, CCD_ZERO, CCD_ZERO, CCD_ZERO);
scale = CCD_ZERO;
if (len % 2 == 1)
len++;
for (i = 0; i < len / 2; i++){
ccdVec3Add(pos, &vs[i]->v.v1);
ccdVec3Add(pos, &vs[i]->v.v2);
scale += CCD_REAL(2.);
}
ccdVec3Scale(pos, CCD_ONE / scale);
free(vs);
return 0;
}
int ccdGJKPenetration(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos)
{
ccd_pt_t polytope;
ccd_pt_el_t *nearest;
int ret;
ccdPtInit(&polytope);
ret = __ccdGJKEPA(obj1, obj2, ccd, &polytope, &nearest);
// set separation vector
if (ret == 0 && nearest){
// compute depth of penetration
*depth = CCD_SQRT(nearest->dist);
// store normalized direction vector
ccdVec3Copy(dir, &nearest->witness);
ccdVec3Normalize(dir);
// compute position
if (penEPAPos(&polytope, nearest, pos) != 0){
ccdPtDestroy(&polytope);
return -2;
}
}
ccdPtDestroy(&polytope);
return ret;
}
static int __ccdGJK(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_simplex_t *simplex)
{
unsigned long iterations;
ccd_vec3_t dir; // direction vector
ccd_support_t last; // last support point
int do_simplex_res;
// initialize simplex struct
ccdSimplexInit(simplex);
// get first direction
ccd->first_dir(obj1, obj2, &dir);
// get first support point
__ccdSupport(obj1, obj2, &dir, ccd, &last);
// and add this point to simplex as last one
ccdSimplexAdd(simplex, &last);
// set up direction vector to as (O - last) which is exactly -last
ccdVec3Copy(&dir, &last.v);
ccdVec3Scale(&dir, -CCD_ONE);
// start iterations
for (iterations = 0UL; iterations < ccd->max_iterations; ++iterations) {
// obtain support point
__ccdSupport(obj1, obj2, &dir, ccd, &last);
// check if farthest point in Minkowski difference in direction dir
// isn't somewhere before origin (the test on negative dot product)
// - because if it is, objects are not intersecting at all.
if (ccdVec3Dot(&last.v, &dir) < CCD_ZERO){
return -1; // intersection not found
}
// add last support vector to simplex
ccdSimplexAdd(simplex, &last);
// if doSimplex returns 1 if objects intersect, -1 if objects don't
// intersect and 0 if algorithm should continue
do_simplex_res = doSimplex(simplex, &dir);
if (do_simplex_res == 1){
return 0; // intersection found
}else if (do_simplex_res == -1){
return -1; // intersection not found
}
if (ccdIsZero(ccdVec3Len2(&dir))){
return -1; // intersection not found
}
}
// intersection wasn't found
return -1;
}
static int __ccdGJKEPA(const void *obj1, const void *obj2,
const ccd_t *ccd,
ccd_pt_t *polytope, ccd_pt_el_t **nearest)
{
ccd_simplex_t simplex;
ccd_support_t supp; // support point
int ret, size;
*nearest = NULL;
// run GJK and obtain terminal simplex
ret = __ccdGJK(obj1, obj2, ccd, &simplex);
if (ret != 0)
return -1;
// transform simplex to polytope - simplex won't be used anymore
size = ccdSimplexSize(&simplex);
if (size == 4){
ret = simplexToPolytope4(obj1, obj2, ccd, &simplex, polytope, nearest);
}else if (size == 3){
ret = simplexToPolytope3(obj1, obj2, ccd, &simplex, polytope, nearest);
}else{ // size == 2
ret = simplexToPolytope2(obj1, obj2, ccd, &simplex, polytope, nearest);
}
if (ret == -1){
// touching contact
return 0;
}else if (ret == -2){
// failed memory allocation
return -2;
}
while (1){
// get triangle nearest to origin
*nearest = ccdPtNearest(polytope);
// get next support point
if (nextSupport(obj1, obj2, ccd, *nearest, &supp) != 0)
break;
// expand nearest triangle using new point - supp
if (expandPolytope(polytope, *nearest, &supp) != 0)
return -2;
}
return 0;
}
static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir)
{
const ccd_support_t *A, *B;
ccd_vec3_t AB, AO, tmp;
ccd_real_t dot;
// get last added as A
A = ccdSimplexLast(simplex);
// get the other point
B = ccdSimplexPoint(simplex, 0);
// compute AB oriented segment
ccdVec3Sub2(&AB, &B->v, &A->v);
// compute AO vector
ccdVec3Copy(&AO, &A->v);
ccdVec3Scale(&AO, -CCD_ONE);
// dot product AB . AO
dot = ccdVec3Dot(&AB, &AO);
// check if origin doesn't lie on AB segment
ccdVec3Cross(&tmp, &AB, &AO);
if (ccdIsZero(ccdVec3Len2(&tmp)) && dot > CCD_ZERO){
return 1;
}
// check if origin is in area where AB segment is
if (ccdIsZero(dot) || dot < CCD_ZERO){
// origin is in outside are of A
ccdSimplexSet(simplex, 0, A);
ccdSimplexSetSize(simplex, 1);
ccdVec3Copy(dir, &AO);
}else{
// origin is in area where AB segment is
// keep simplex untouched and set direction to
// AB x AO x AB
tripleCross(&AB, &AO, &AB, dir);
}
return 0;
}
static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir)
{
const ccd_support_t *A, *B, *C;
ccd_vec3_t AO, AB, AC, ABC, tmp;
ccd_real_t dot, dist;
// get last added as A
A = ccdSimplexLast(simplex);
// get the other points
B = ccdSimplexPoint(simplex, 1);
C = ccdSimplexPoint(simplex, 0);
// check touching contact
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL);
if (ccdIsZero(dist)){
return 1;
}
// check if triangle is really triangle (has area > 0)
// if not simplex can't be expanded and thus no itersection is found
if (ccdVec3Eq(&A->v, &B->v) || ccdVec3Eq(&A->v, &C->v)){
return -1;
}
// compute AO vector
ccdVec3Copy(&AO, &A->v);
ccdVec3Scale(&AO, -CCD_ONE);
// compute AB and AC segments and ABC vector (perpendircular to triangle)
ccdVec3Sub2(&AB, &B->v, &A->v);
ccdVec3Sub2(&AC, &C->v, &A->v);
ccdVec3Cross(&ABC, &AB, &AC);
ccdVec3Cross(&tmp, &ABC, &AC);
dot = ccdVec3Dot(&tmp, &AO);
if (ccdIsZero(dot) || dot > CCD_ZERO){
dot = ccdVec3Dot(&AC, &AO);
if (ccdIsZero(dot) || dot > CCD_ZERO){
// C is already in place
ccdSimplexSet(simplex, 1, A);
ccdSimplexSetSize(simplex, 2);
tripleCross(&AC, &AO, &AC, dir);
}else{
ccd_do_simplex3_45:
dot = ccdVec3Dot(&AB, &AO);
if (ccdIsZero(dot) || dot > CCD_ZERO){
ccdSimplexSet(simplex, 0, B);
ccdSimplexSet(simplex, 1, A);
ccdSimplexSetSize(simplex, 2);
tripleCross(&AB, &AO, &AB, dir);
}else{
ccdSimplexSet(simplex, 0, A);
ccdSimplexSetSize(simplex, 1);
ccdVec3Copy(dir, &AO);
}
}
}else{
ccdVec3Cross(&tmp, &AB, &ABC);
dot = ccdVec3Dot(&tmp, &AO);
if (ccdIsZero(dot) || dot > CCD_ZERO){
goto ccd_do_simplex3_45;
}else{
dot = ccdVec3Dot(&ABC, &AO);
if (ccdIsZero(dot) || dot > CCD_ZERO){
ccdVec3Copy(dir, &ABC);
}else{
ccd_support_t Ctmp;
ccdSupportCopy(&Ctmp, C);
ccdSimplexSet(simplex, 0, B);
ccdSimplexSet(simplex, 1, &Ctmp);
ccdVec3Copy(dir, &ABC);
ccdVec3Scale(dir, -CCD_ONE);
}
}
}
return 0;
}
static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir)
{
const ccd_support_t *A, *B, *C, *D;
ccd_vec3_t AO, AB, AC, AD, ABC, ACD, ADB;
int B_on_ACD, C_on_ADB, D_on_ABC;
int AB_O, AC_O, AD_O;
ccd_real_t dist;
// get last added as A
A = ccdSimplexLast(simplex);
// get the other points
B = ccdSimplexPoint(simplex, 2);
C = ccdSimplexPoint(simplex, 1);
D = ccdSimplexPoint(simplex, 0);
// check if tetrahedron is really tetrahedron (has volume > 0)
// if it is not simplex can't be expanded and thus no intersection is
// found
dist = ccdVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, NULL);
if (ccdIsZero(dist)){
return -1;
}
// check if origin lies on some of tetrahedron's face - if so objects
// intersect
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL);
if (ccdIsZero(dist))
return 1;
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &C->v, &D->v, NULL);
if (ccdIsZero(dist))
return 1;
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &D->v, NULL);
if (ccdIsZero(dist))
return 1;
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &B->v, &C->v, &D->v, NULL);
if (ccdIsZero(dist))
return 1;
// compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors
ccdVec3Copy(&AO, &A->v);
ccdVec3Scale(&AO, -CCD_ONE);
ccdVec3Sub2(&AB, &B->v, &A->v);
ccdVec3Sub2(&AC, &C->v, &A->v);
ccdVec3Sub2(&AD, &D->v, &A->v);
ccdVec3Cross(&ABC, &AB, &AC);
ccdVec3Cross(&ACD, &AC, &AD);
ccdVec3Cross(&ADB, &AD, &AB);
// side (positive or negative) of B, C, D relative to planes ACD, ADB
// and ABC respectively
B_on_ACD = ccdSign(ccdVec3Dot(&ACD, &AB));
C_on_ADB = ccdSign(ccdVec3Dot(&ADB, &AC));
D_on_ABC = ccdSign(ccdVec3Dot(&ABC, &AD));
// whether origin is on same side of ACD, ADB, ABC as B, C, D
// respectively
AB_O = ccdSign(ccdVec3Dot(&ACD, &AO)) == B_on_ACD;
AC_O = ccdSign(ccdVec3Dot(&ADB, &AO)) == C_on_ADB;
AD_O = ccdSign(ccdVec3Dot(&ABC, &AO)) == D_on_ABC;
if (AB_O && AC_O && AD_O){
// origin is in tetrahedron
return 1;
// rearrange simplex to triangle and call doSimplex3()
}else if (!AB_O){
// B is farthest from the origin among all of the tetrahedron's
// points, so remove it from the list and go on with the triangle
// case
// D and C are in place
ccdSimplexSet(simplex, 2, A);
ccdSimplexSetSize(simplex, 3);
}else if (!AC_O){
// C is farthest
ccdSimplexSet(simplex, 1, D);
ccdSimplexSet(simplex, 0, B);
ccdSimplexSet(simplex, 2, A);
ccdSimplexSetSize(simplex, 3);
}else{ // (!AD_O)
ccdSimplexSet(simplex, 0, C);
ccdSimplexSet(simplex, 1, B);
ccdSimplexSet(simplex, 2, A);
ccdSimplexSetSize(simplex, 3);
}
return doSimplex3(simplex, dir);
}
static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir)
{
if (ccdSimplexSize(simplex) == 2){
// simplex contains segment only one segment
return doSimplex2(simplex, dir);
}else if (ccdSimplexSize(simplex) == 3){
// simplex contains triangle
return doSimplex3(simplex, dir);
}else{ // ccdSimplexSize(simplex) == 4
// tetrahedron - this is the only shape which can encapsule origin
// so doSimplex4() also contains test on it
return doSimplex4(simplex, dir);
}
}
_ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b,
const ccd_vec3_t *c, ccd_vec3_t *d)
{
ccd_vec3_t e;
ccdVec3Cross(&e, a, b);
ccdVec3Cross(d, &e, c);
}
/** Transforms simplex to polytope. It is assumed that simplex has 4
* vertices! */
static int simplexToPolytope4(const void *obj1, const void *obj2,
const ccd_t *ccd,
ccd_simplex_t *simplex,
ccd_pt_t *pt, ccd_pt_el_t **nearest)
{
const ccd_support_t *a, *b, *c, *d;
int use_polytope3;
ccd_real_t dist;
ccd_pt_vertex_t *v[4];
ccd_pt_edge_t *e[6];
size_t i;
a = ccdSimplexPoint(simplex, 0);
b = ccdSimplexPoint(simplex, 1);
c = ccdSimplexPoint(simplex, 2);
d = ccdSimplexPoint(simplex, 3);
// check if origin lies on some of tetrahedron's face - if so use
// simplexToPolytope3()
use_polytope3 = 0;
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &c->v, NULL);
if (ccdIsZero(dist)){
use_polytope3 = 1;
}
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &c->v, &d->v, NULL);
if (ccdIsZero(dist)){
use_polytope3 = 1;
ccdSimplexSet(simplex, 1, c);
ccdSimplexSet(simplex, 2, d);
}
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &d->v, NULL);
if (ccdIsZero(dist)){
use_polytope3 = 1;
ccdSimplexSet(simplex, 2, d);
}
dist = ccdVec3PointTriDist2(ccd_vec3_origin, &b->v, &c->v, &d->v, NULL);
if (ccdIsZero(dist)){
use_polytope3 = 1;
ccdSimplexSet(simplex, 0, b);
ccdSimplexSet(simplex, 1, c);
ccdSimplexSet(simplex, 2, d);
}
if (use_polytope3){
ccdSimplexSetSize(simplex, 3);
return simplexToPolytope3(obj1, obj2, ccd, simplex, pt, nearest);
}
// no touching contact - simply create tetrahedron
for (i = 0; i < 4; i++){
v[i] = ccdPtAddVertex(pt, ccdSimplexPoint(simplex, i));
}
e[0] = ccdPtAddEdge(pt, v[0], v[1]);
e[1] = ccdPtAddEdge(pt, v[1], v[2]);
e[2] = ccdPtAddEdge(pt, v[2], v[0]);
e[3] = ccdPtAddEdge(pt, v[3], v[0]);
e[4] = ccdPtAddEdge(pt, v[3], v[1]);
e[5] = ccdPtAddEdge(pt, v[3], v[2]);
// ccdPtAdd*() functions return NULL either if the memory allocation
// failed of if any of the input pointers are NULL, so the bad
// allocation can be checked by the last calls of ccdPtAddFace()
// because the rest of the bad allocations eventually "bubble up" here
if (ccdPtAddFace(pt, e[0], e[1], e[2]) == NULL
|| ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL
|| ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL
|| ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL){
return -2;
}
return 0;
}
/** Transforms simplex to polytope, three vertices required */
static int simplexToPolytope3(const void *obj1, const void *obj2,
const ccd_t *ccd,
const ccd_simplex_t *simplex,
ccd_pt_t *pt, ccd_pt_el_t **nearest)
{
const ccd_support_t *a, *b, *c;
ccd_support_t d, d2;
ccd_vec3_t ab, ac, dir;
ccd_pt_vertex_t *v[5];
ccd_pt_edge_t *e[9];
ccd_real_t dist, dist2;
*nearest = NULL;
a = ccdSimplexPoint(simplex, 0);
b = ccdSimplexPoint(simplex, 1);
c = ccdSimplexPoint(simplex, 2);
// If only one triangle left from previous GJK run origin lies on this
// triangle. So it is necessary to expand triangle into two
// tetrahedrons connected with base (which is exactly abc triangle).
// get next support point in direction of normal of triangle
ccdVec3Sub2(&ab, &b->v, &a->v);
ccdVec3Sub2(&ac, &c->v, &a->v);
ccdVec3Cross(&dir, &ab, &ac);
__ccdSupport(obj1, obj2, &dir, ccd, &d);
dist = ccdVec3PointTriDist2(&d.v, &a->v, &b->v, &c->v, NULL);
// and second one take in opposite direction
ccdVec3Scale(&dir, -CCD_ONE);
__ccdSupport(obj1, obj2, &dir, ccd, &d2);
dist2 = ccdVec3PointTriDist2(&d2.v, &a->v, &b->v, &c->v, NULL);
// check if face isn't already on edge of minkowski sum and thus we
// have touching contact
if (ccdIsZero(dist) || ccdIsZero(dist2)){
v[0] = ccdPtAddVertex(pt, a);
v[1] = ccdPtAddVertex(pt, b);
v[2] = ccdPtAddVertex(pt, c);
e[0] = ccdPtAddEdge(pt, v[0], v[1]);
e[1] = ccdPtAddEdge(pt, v[1], v[2]);
e[2] = ccdPtAddEdge(pt, v[2], v[0]);
*nearest = (ccd_pt_el_t *)ccdPtAddFace(pt, e[0], e[1], e[2]);
if (*nearest == NULL)
return -2;
return -1;
}
// form polyhedron
v[0] = ccdPtAddVertex(pt, a);
v[1] = ccdPtAddVertex(pt, b);
v[2] = ccdPtAddVertex(pt, c);
v[3] = ccdPtAddVertex(pt, &d);
v[4] = ccdPtAddVertex(pt, &d2);
e[0] = ccdPtAddEdge(pt, v[0], v[1]);
e[1] = ccdPtAddEdge(pt, v[1], v[2]);
e[2] = ccdPtAddEdge(pt, v[2], v[0]);
e[3] = ccdPtAddEdge(pt, v[3], v[0]);
e[4] = ccdPtAddEdge(pt, v[3], v[1]);
e[5] = ccdPtAddEdge(pt, v[3], v[2]);
e[6] = ccdPtAddEdge(pt, v[4], v[0]);
e[7] = ccdPtAddEdge(pt, v[4], v[1]);
e[8] = ccdPtAddEdge(pt, v[4], v[2]);
if (ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL
|| ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL
|| ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL
|| ccdPtAddFace(pt, e[6], e[7], e[0]) == NULL
|| ccdPtAddFace(pt, e[7], e[8], e[1]) == NULL
|| ccdPtAddFace(pt, e[8], e[6], e[2]) == NULL){
return -2;
}
return 0;
}
/** Transforms simplex to polytope, two vertices required */
static int simplexToPolytope2(const void *obj1, const void *obj2,
const ccd_t *ccd,
const ccd_simplex_t *simplex,
ccd_pt_t *pt, ccd_pt_el_t **nearest)
{
const ccd_support_t *a, *b;
ccd_vec3_t ab, ac, dir;
ccd_support_t supp[4];
ccd_pt_vertex_t *v[6];
ccd_pt_edge_t *e[12];
size_t i;
int found;
a = ccdSimplexPoint(simplex, 0);
b = ccdSimplexPoint(simplex, 1);
// This situation is a bit tricky. If only one segment comes from
// previous run of GJK - it means that either this segment is on
// minkowski edge (and thus we have touch contact) or it it isn't and
// therefore segment is somewhere *inside* minkowski sum and it *must*
// be possible to fully enclose this segment with polyhedron formed by
// at least 8 triangle faces.
// get first support point (any)
found = 0;
for (i = 0; i < ccd_points_on_sphere_len; i++){
__ccdSupport(obj1, obj2, &ccd_points_on_sphere[i], ccd, &supp[0]);
if (!ccdVec3Eq(&a->v, &supp[0].v) && !ccdVec3Eq(&b->v, &supp[0].v)){
found = 1;
break;
}
}
if (!found)
goto simplexToPolytope2_touching_contact;
// get second support point in opposite direction than supp[0]
ccdVec3Copy(&dir, &supp[0].v);
ccdVec3Scale(&dir, -CCD_ONE);
__ccdSupport(obj1, obj2, &dir, ccd, &supp[1]);
if (ccdVec3Eq(&a->v, &supp[1].v) || ccdVec3Eq(&b->v, &supp[1].v))
goto simplexToPolytope2_touching_contact;
// next will be in direction of normal of triangle a,supp[0],supp[1]
ccdVec3Sub2(&ab, &supp[0].v, &a->v);
ccdVec3Sub2(&ac, &supp[1].v, &a->v);
ccdVec3Cross(&dir, &ab, &ac);
__ccdSupport(obj1, obj2, &dir, ccd, &supp[2]);
if (ccdVec3Eq(&a->v, &supp[2].v) || ccdVec3Eq(&b->v, &supp[2].v))
goto simplexToPolytope2_touching_contact;
// and last one will be in opposite direction
ccdVec3Scale(&dir, -CCD_ONE);
__ccdSupport(obj1, obj2, &dir, ccd, &supp[3]);
if (ccdVec3Eq(&a->v, &supp[3].v) || ccdVec3Eq(&b->v, &supp[3].v))
goto simplexToPolytope2_touching_contact;
goto simplexToPolytope2_not_touching_contact;
simplexToPolytope2_touching_contact:
v[0] = ccdPtAddVertex(pt, a);
v[1] = ccdPtAddVertex(pt, b);
*nearest = (ccd_pt_el_t *)ccdPtAddEdge(pt, v[0], v[1]);
if (*nearest == NULL)
return -2;
return -1;
simplexToPolytope2_not_touching_contact:
// form polyhedron
v[0] = ccdPtAddVertex(pt, a);
v[1] = ccdPtAddVertex(pt, &supp[0]);
v[2] = ccdPtAddVertex(pt, b);
v[3] = ccdPtAddVertex(pt, &supp[1]);
v[4] = ccdPtAddVertex(pt, &supp[2]);
v[5] = ccdPtAddVertex(pt, &supp[3]);
e[0] = ccdPtAddEdge(pt, v[0], v[1]);
e[1] = ccdPtAddEdge(pt, v[1], v[2]);
e[2] = ccdPtAddEdge(pt, v[2], v[3]);
e[3] = ccdPtAddEdge(pt, v[3], v[0]);
e[4] = ccdPtAddEdge(pt, v[4], v[0]);
e[5] = ccdPtAddEdge(pt, v[4], v[1]);
e[6] = ccdPtAddEdge(pt, v[4], v[2]);
e[7] = ccdPtAddEdge(pt, v[4], v[3]);
e[8] = ccdPtAddEdge(pt, v[5], v[0]);
e[9] = ccdPtAddEdge(pt, v[5], v[1]);
e[10] = ccdPtAddEdge(pt, v[5], v[2]);
e[11] = ccdPtAddEdge(pt, v[5], v[3]);
if (ccdPtAddFace(pt, e[4], e[5], e[0]) == NULL
|| ccdPtAddFace(pt, e[5], e[6], e[1]) == NULL
|| ccdPtAddFace(pt, e[6], e[7], e[2]) == NULL
|| ccdPtAddFace(pt, e[7], e[4], e[3]) == NULL
|| ccdPtAddFace(pt, e[8], e[9], e[0]) == NULL
|| ccdPtAddFace(pt, e[9], e[10], e[1]) == NULL
|| ccdPtAddFace(pt, e[10], e[11], e[2]) == NULL
|| ccdPtAddFace(pt, e[11], e[8], e[3]) == NULL){
return -2;
}
return 0;
}
/** Expands polytope's tri by new vertex v. Triangle tri is replaced by
* three triangles each with one vertex in v. */
static int expandPolytope(ccd_pt_t *pt, ccd_pt_el_t *el,
const ccd_support_t *newv)
{
ccd_pt_vertex_t *v[5];
ccd_pt_edge_t *e[8];
ccd_pt_face_t *f[2];
// element can be either segment or triangle
if (el->type == CCD_PT_EDGE){
// In this case, segment should be replaced by new point.
// Simpliest case is when segment stands alone and in this case
// this segment is replaced by two other segments both connected to
// newv.
// Segment can be also connected to max two faces and in that case
// each face must be replaced by two other faces. To do this
// correctly it is necessary to have correctly ordered edges and
// vertices which is exactly what is done in following code.
//
ccdPtEdgeVertices((const ccd_pt_edge_t *)el, &v[0], &v[2]);
ccdPtEdgeFaces((ccd_pt_edge_t *)el, &f[0], &f[1]);
if (f[0]){
ccdPtFaceEdges(f[0], &e[0], &e[1], &e[2]);
if (e[0] == (ccd_pt_edge_t *)el){
e[0] = e[2];
}else if (e[1] == (ccd_pt_edge_t *)el){
e[1] = e[2];
}
ccdPtEdgeVertices(e[0], &v[1], &v[3]);
if (v[1] != v[0] && v[3] != v[0]){
e[2] = e[0];
e[0] = e[1];
e[1] = e[2];
if (v[1] == v[2])
v[1] = v[3];
}else{
if (v[1] == v[0])
v[1] = v[3];
}
if (f[1]){
ccdPtFaceEdges(f[1], &e[2], &e[3], &e[4]);
if (e[2] == (ccd_pt_edge_t *)el){
e[2] = e[4];
}else if (e[3] == (ccd_pt_edge_t *)el){
e[3] = e[4];
}
ccdPtEdgeVertices(e[2], &v[3], &v[4]);
if (v[3] != v[2] && v[4] != v[2]){
e[4] = e[2];
e[2] = e[3];
e[3] = e[4];
if (v[3] == v[0])
v[3] = v[4];
}else{
if (v[3] == v[2])
v[3] = v[4];
}
}
v[4] = ccdPtAddVertex(pt, newv);
ccdPtDelFace(pt, f[0]);
if (f[1]){
ccdPtDelFace(pt, f[1]);
ccdPtDelEdge(pt, (ccd_pt_edge_t *)el);
}
e[4] = ccdPtAddEdge(pt, v[4], v[2]);
e[5] = ccdPtAddEdge(pt, v[4], v[0]);
e[6] = ccdPtAddEdge(pt, v[4], v[1]);
if (f[1])
e[7] = ccdPtAddEdge(pt, v[4], v[3]);
if (ccdPtAddFace(pt, e[1], e[4], e[6]) == NULL
|| ccdPtAddFace(pt, e[0], e[6], e[5]) == NULL){
return -2;
}
if (f[1]){
if (ccdPtAddFace(pt, e[3], e[5], e[7]) == NULL
|| ccdPtAddFace(pt, e[4], e[7], e[2]) == NULL){
return -2;
}
}else{
if (ccdPtAddFace(pt, e[4], e[5], (ccd_pt_edge_t *)el) == NULL)
return -2;
}
}
}else{ // el->type == CCD_PT_FACE
// replace triangle by tetrahedron without base (base would be the
// triangle that will be removed)
// get triplet of surrounding edges and vertices of triangle face
ccdPtFaceEdges((const ccd_pt_face_t *)el, &e[0], &e[1], &e[2]);
ccdPtEdgeVertices(e[0], &v[0], &v[1]);
ccdPtEdgeVertices(e[1], &v[2], &v[3]);
// following code sorts edges to have e[0] between vertices 0-1,
// e[1] between 1-2 and e[2] between 2-0
if (v[2] != v[1] && v[3] != v[1]){
// swap e[1] and e[2]
e[3] = e[1];
e[1] = e[2];
e[2] = e[3];
}
if (v[3] != v[0] && v[3] != v[1])
v[2] = v[3];
// remove triangle face
ccdPtDelFace(pt, (ccd_pt_face_t *)el);
// expand triangle to tetrahedron
v[3] = ccdPtAddVertex(pt, newv);
e[3] = ccdPtAddEdge(pt, v[3], v[0]);
e[4] = ccdPtAddEdge(pt, v[3], v[1]);
e[5] = ccdPtAddEdge(pt, v[3], v[2]);
if (ccdPtAddFace(pt, e[3], e[4], e[0]) == NULL
|| ccdPtAddFace(pt, e[4], e[5], e[1]) == NULL
|| ccdPtAddFace(pt, e[5], e[3], e[2]) == NULL){
return -2;
}
}
return 0;
}
/** Finds next support point (and stores it in out argument).
* Returns 0 on success, -1 otherwise */
static int nextSupport(const void *obj1, const void *obj2, const ccd_t *ccd,
const ccd_pt_el_t *el,
ccd_support_t *out)
{
ccd_vec3_t *a, *b, *c;
ccd_real_t dist;
if (el->type == CCD_PT_VERTEX)
return -1;
// touch contact
if (ccdIsZero(el->dist))
return -1;
__ccdSupport(obj1, obj2, &el->witness, ccd, out);
// Compute dist of support point along element witness point direction
// so we can determine whether we expanded a polytope surrounding the
// origin a bit.
dist = ccdVec3Dot(&out->v, &el->witness);
if (dist - el->dist < ccd->epa_tolerance)
return -1;
if (el->type == CCD_PT_EDGE){
// fetch end points of edge
ccdPtEdgeVec3((ccd_pt_edge_t *)el, &a, &b);
// get distance from segment
dist = ccdVec3PointSegmentDist2(&out->v, a, b, NULL);
}else{ // el->type == CCD_PT_FACE
// fetch vertices of triangle face
ccdPtFaceVec3((ccd_pt_face_t *)el, &a, &b, &c);
// check if new point can significantly expand polytope
dist = ccdVec3PointTriDist2(&out->v, a, b, c, NULL);
}
if (dist < ccd->epa_tolerance)
return -1;
return 0;
}

@ -1,154 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010,2011 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_H__
#define __CCD_H__
#include <ccd/vec3.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Type of *support* function that takes pointer to 3D object and direction
* and returns (via vec argument) furthest point from object in specified
* direction.
*/
typedef void (*ccd_support_fn)(const void *obj, const ccd_vec3_t *dir,
ccd_vec3_t *vec);
/**
* Returns (via dir argument) first direction vector that will be used in
* initialization of algorithm.
*/
typedef void (*ccd_first_dir_fn)(const void *obj1, const void *obj2,
ccd_vec3_t *dir);
/**
* Returns (via center argument) geometric center (some point near center)
* of given object.
*/
typedef void (*ccd_center_fn)(const void *obj1, ccd_vec3_t *center);
/**
* Main structure of CCD algorithm.
*/
struct _ccd_t {
ccd_first_dir_fn first_dir; //!< Returns initial direction where first
//!< support point will be searched
ccd_support_fn support1; //!< Function that returns support point of
//!< first object
ccd_support_fn support2; //!< Function that returns support point of
//!< second object
ccd_center_fn center1; //!< Function that returns geometric center of
//!< first object
ccd_center_fn center2; //!< Function that returns geometric center of
//!< second object
unsigned long max_iterations; //!< Maximal number of iterations
ccd_real_t epa_tolerance;
ccd_real_t mpr_tolerance; //!< Boundary tolerance for MPR algorithm
ccd_real_t dist_tolerance;
};
typedef struct _ccd_t ccd_t;
/**
* Default first direction.
*/
CCD_EXPORT void ccdFirstDirDefault(const void *o1, const void *o2,
ccd_vec3_t *dir);
#define CCD_INIT(ccd) \
do { \
(ccd)->first_dir = ccdFirstDirDefault; \
(ccd)->support1 = NULL; \
(ccd)->support2 = NULL; \
(ccd)->center1 = NULL; \
(ccd)->center2 = NULL; \
\
(ccd)->max_iterations = (unsigned long)-1; \
(ccd)->epa_tolerance = CCD_REAL(0.0001); \
(ccd)->mpr_tolerance = CCD_REAL(0.0001); \
(ccd)->dist_tolerance = CCD_REAL(1E-6); \
} while(0)
/**
* Returns true if two given objects interest.
*/
CCD_EXPORT int ccdGJKIntersect(const void *obj1, const void *obj2,
const ccd_t *ccd);
/**
* This function computes separation vector of two objects. Separation
* vector is minimal translation of obj2 to get obj1 and obj2 speparated
* (without intersection).
* Returns 0 if obj1 and obj2 intersect and sep is filled with translation
* vector. If obj1 and obj2 don't intersect -1 is returned.
* If memory allocation fails -2 is returned.
*/
CCD_EXPORT int ccdGJKSeparate(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_vec3_t *sep);
/**
* Computes penetration of obj2 into obj1.
* Depth of penetration, direction and position is returned. It means that
* if obj2 is translated by distance depth in direction dir objects will
* have touching contact, pos should be position in global coordinates
* where force should take a place.
*
* CCD+EPA algorithm is used.
*
* Returns 0 if obj1 and obj2 intersect and depth, dir and pos are filled
* if given non-NULL pointers.
* If obj1 and obj2 don't intersect -1 is returned.
* If memory allocation fails -2 is returned.
*/
CCD_EXPORT int ccdGJKPenetration(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_real_t *depth,
ccd_vec3_t *dir, ccd_vec3_t *pos);
/**
* Returns true if two given objects intersect - MPR algorithm is used.
*/
CCD_EXPORT int ccdMPRIntersect(const void *obj1, const void *obj2,
const ccd_t *ccd);
/**
* Computes penetration of obj2 into obj1.
* Depth of penetration, direction and position is returned, i.e. if obj2
* is translated by computed depth in resulting direction obj1 and obj2
* would have touching contact. Position is point in global coordinates
* where force should take a place.
*
* Minkowski Portal Refinement algorithm is used (MPR, a.k.a. XenoCollide,
* see Game Programming Gem 7).
*
* Returns 0 if obj1 and obj2 intersect, otherwise -1 is returned.
*/
CCD_EXPORT int ccdMPRPenetration(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_real_t *depth,
ccd_vec3_t *dir, ccd_vec3_t *pos);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_H__ */

@ -1,26 +0,0 @@
#ifndef CCD_EXPORT_H
#define CCD_EXPORT_H
#ifdef CCD_STATIC_DEFINE
# define CCD_EXPORT
#else
# ifdef _MSC_VER
# ifdef ccd_EXPORTS
# define CCD_EXPORT __declspec(dllexport)
# else /* ccd_EXPORTS */
# define CCD_EXPORT __declspec(dllimport)
# endif /* ccd_EXPORTS */
# else
# ifndef CCD_EXPORT
# ifdef ccd_EXPORTS
/* We are building this library */
# define CCD_EXPORT __attribute__((visibility("default")))
# else
/* We are using this library */
# define CCD_EXPORT __attribute__((visibility("default")))
# endif
# endif
# endif
#endif
#endif

@ -1,64 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_COMPILER_H__
#define __CCD_COMPILER_H__
#include <stddef.h>
#define ccd_offsetof(TYPE, MEMBER) offsetof(TYPE, MEMBER)
#define ccd_container_of(ptr, type, member) \
(type *)( (char *)ptr - ccd_offsetof(type, member))
/**
* Marks inline function.
*/
#ifdef __GNUC__
# define _ccd_inline static inline __attribute__((always_inline))
#else /* __GNUC__ */
# define _ccd_inline static __inline
#endif /* __GNUC__ */
/**
* __prefetch(x) - prefetches the cacheline at "x" for read
* __prefetchw(x) - prefetches the cacheline at "x" for write
*/
#ifdef __GNUC__
# define _ccd_prefetch(x) __builtin_prefetch(x)
# define _ccd_prefetchw(x) __builtin_prefetch(x,1)
#else /* __GNUC__ */
# define _ccd_prefetch(x) ((void)0)
# define _ccd_prefetchw(x) ((void)0)
#endif /* __GNUC__ */
#ifdef __ICC
// disable unused parameter warning
# pragma warning(disable:869)
// disable annoying "operands are evaluated in unspecified order" warning
# pragma warning(disable:981)
#endif /* __ICC */
#ifdef _MSC_VER
// disable unsafe function warning
# define _CRT_SECURE_NO_WARNINGS
#endif /* _MSC_VER */
#endif /* __CCD_COMPILER_H__ */

@ -1,7 +0,0 @@
#ifndef __CCD_CONFIG_H__
#define __CCD_CONFIG_H__
#cmakedefine CCD_SINGLE
#cmakedefine CCD_DOUBLE
#endif /* __CCD_CONFIG_H__ */

@ -1,7 +0,0 @@
#ifndef __CCD_CONFIG_H__
#define __CCD_CONFIG_H__
ifdef(`USE_SINGLE', `#define CCD_SINGLE')
ifdef(`USE_DOUBLE', `#define CCD_DOUBLE')
#endif /* __CCD_CONFIG_H__ */

@ -1,231 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_QUAT_H__
#define __CCD_QUAT_H__
#include <ccd/compiler.h>
#include <ccd/vec3.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct _ccd_quat_t {
ccd_real_t q[4]; //!< x, y, z, w
};
typedef struct _ccd_quat_t ccd_quat_t;
#define CCD_QUAT(name, x, y, z, w) \
ccd_quat_t name = { {x, y, z, w} }
_ccd_inline ccd_real_t ccdQuatLen2(const ccd_quat_t *q);
_ccd_inline ccd_real_t ccdQuatLen(const ccd_quat_t *q);
_ccd_inline void ccdQuatSet(ccd_quat_t *q, ccd_real_t x, ccd_real_t y, ccd_real_t z, ccd_real_t w);
_ccd_inline void ccdQuatCopy(ccd_quat_t *dest, const ccd_quat_t *src);
_ccd_inline int ccdQuatNormalize(ccd_quat_t *q);
_ccd_inline void ccdQuatSetAngleAxis(ccd_quat_t *q,
ccd_real_t angle, const ccd_vec3_t *axis);
_ccd_inline void ccdQuatScale(ccd_quat_t *q, ccd_real_t k);
/**
* q = q * q2
*/
_ccd_inline void ccdQuatMul(ccd_quat_t *q, const ccd_quat_t *q2);
/**
* q = a * b
*/
_ccd_inline void ccdQuatMul2(ccd_quat_t *q,
const ccd_quat_t *a, const ccd_quat_t *b);
/**
* Inverts quaternion.
* Returns 0 on success.
*/
_ccd_inline int ccdQuatInvert(ccd_quat_t *q);
_ccd_inline int ccdQuatInvert2(ccd_quat_t *dest, const ccd_quat_t *src);
/**
* Rotate vector v by quaternion q.
*/
_ccd_inline void ccdQuatRotVec(ccd_vec3_t *v, const ccd_quat_t *q);
/**** INLINES ****/
_ccd_inline ccd_real_t ccdQuatLen2(const ccd_quat_t *q)
{
ccd_real_t len;
len = q->q[0] * q->q[0];
len += q->q[1] * q->q[1];
len += q->q[2] * q->q[2];
len += q->q[3] * q->q[3];
return len;
}
_ccd_inline ccd_real_t ccdQuatLen(const ccd_quat_t *q)
{
return CCD_SQRT(ccdQuatLen2(q));
}
_ccd_inline void ccdQuatSet(ccd_quat_t *q, ccd_real_t x, ccd_real_t y, ccd_real_t z, ccd_real_t w)
{
q->q[0] = x;
q->q[1] = y;
q->q[2] = z;
q->q[3] = w;
}
_ccd_inline void ccdQuatCopy(ccd_quat_t *dest, const ccd_quat_t *src)
{
*dest = *src;
}
_ccd_inline int ccdQuatNormalize(ccd_quat_t *q)
{
ccd_real_t len = ccdQuatLen(q);
if (len < CCD_EPS)
return 0;
ccdQuatScale(q, CCD_ONE / len);
return 1;
}
_ccd_inline void ccdQuatSetAngleAxis(ccd_quat_t *q,
ccd_real_t angle, const ccd_vec3_t *axis)
{
ccd_real_t a, x, y, z, n, s;
a = angle/2;
x = ccdVec3X(axis);
y = ccdVec3Y(axis);
z = ccdVec3Z(axis);
n = CCD_SQRT(x*x + y*y + z*z);
// axis==0? (treat this the same as angle==0 with an arbitrary axis)
if (n < CCD_EPS){
q->q[0] = q->q[1] = q->q[2] = CCD_ZERO;
q->q[3] = CCD_ONE;
}else{
s = sin(a)/n;
q->q[3] = cos(a);
q->q[0] = x*s;
q->q[1] = y*s;
q->q[2] = z*s;
ccdQuatNormalize(q);
}
}
_ccd_inline void ccdQuatScale(ccd_quat_t *q, ccd_real_t k)
{
size_t i;
for (i = 0; i < 4; i++)
q->q[i] *= k;
}
_ccd_inline void ccdQuatMul(ccd_quat_t *q, const ccd_quat_t *q2)
{
ccd_quat_t a;
ccdQuatCopy(&a, q);
ccdQuatMul2(q, &a, q2);
}
_ccd_inline void ccdQuatMul2(ccd_quat_t *q,
const ccd_quat_t *a, const ccd_quat_t *b)
{
q->q[0] = a->q[3] * b->q[0]
+ a->q[0] * b->q[3]
+ a->q[1] * b->q[2]
- a->q[2] * b->q[1];
q->q[1] = a->q[3] * b->q[1]
+ a->q[1] * b->q[3]
- a->q[0] * b->q[2]
+ a->q[2] * b->q[0];
q->q[2] = a->q[3] * b->q[2]
+ a->q[2] * b->q[3]
+ a->q[0] * b->q[1]
- a->q[1] * b->q[0];
q->q[3] = a->q[3] * b->q[3]
- a->q[0] * b->q[0]
- a->q[1] * b->q[1]
- a->q[2] * b->q[2];
}
_ccd_inline int ccdQuatInvert(ccd_quat_t *q)
{
ccd_real_t len2 = ccdQuatLen2(q);
if (len2 < CCD_EPS)
return -1;
len2 = CCD_ONE / len2;
q->q[0] = -q->q[0] * len2;
q->q[1] = -q->q[1] * len2;
q->q[2] = -q->q[2] * len2;
q->q[3] = q->q[3] * len2;
return 0;
}
_ccd_inline int ccdQuatInvert2(ccd_quat_t *dest, const ccd_quat_t *src)
{
ccdQuatCopy(dest, src);
return ccdQuatInvert(dest);
}
_ccd_inline void ccdQuatRotVec(ccd_vec3_t *v, const ccd_quat_t *q)
{
// original version: 31 mul + 21 add
// optimized version: 18 mul + 12 add
// formula: v = v + 2 * cross(q.xyz, cross(q.xyz, v) + q.w * v)
ccd_real_t cross1_x, cross1_y, cross1_z, cross2_x, cross2_y, cross2_z;
ccd_real_t x, y, z, w;
ccd_real_t vx, vy, vz;
vx = ccdVec3X(v);
vy = ccdVec3Y(v);
vz = ccdVec3Z(v);
w = q->q[3];
x = q->q[0];
y = q->q[1];
z = q->q[2];
cross1_x = y * vz - z * vy + w * vx;
cross1_y = z * vx - x * vz + w * vy;
cross1_z = x * vy - y * vx + w * vz;
cross2_x = y * cross1_z - z * cross1_y;
cross2_y = z * cross1_x - x * cross1_z;
cross2_z = x * cross1_y - y * cross1_x;
ccdVec3Set(v, vx + 2 * cross2_x, vy + 2 * cross2_y, vz + 2 * cross2_z);
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_QUAT_H__ */

@ -1,340 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010-2013 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_VEC3_H__
#define __CCD_VEC3_H__
#include <math.h>
#include <float.h>
#include <stdlib.h>
#include <ccd/compiler.h>
#include <ccd/config.h>
#include <ccd/ccd_export.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef CCD_SINGLE
# ifndef CCD_DOUBLE
# error You must define CCD_SINGLE or CCD_DOUBLE
# endif /* CCD_DOUBLE */
#endif /* CCD_SINGLE */
#ifdef WIN32
# define CCD_FMIN(x, y) ((x) < (y) ? (x) : (y))
#endif /* WIN32 */
#ifdef CCD_SINGLE
# ifdef CCD_DOUBLE
# error You can define either CCD_SINGLE or CCD_DOUBLE, not both!
# endif /* CCD_DOUBLE */
typedef float ccd_real_t;
//# define CCD_EPS 1E-6
# define CCD_EPS FLT_EPSILON
# define CCD_REAL_MAX FLT_MAX
# define CCD_REAL(x) (x ## f) /*!< form a constant */
# define CCD_SQRT(x) (sqrtf(x)) /*!< square root */
# define CCD_FABS(x) (fabsf(x)) /*!< absolute value */
# define CCD_FMAX(x, y) (fmaxf((x), (y))) /*!< maximum of two floats */
# ifndef CCD_FMIN
# define CCD_FMIN(x, y) (fminf((x), (y))) /*!< minimum of two floats */
# endif /* CCD_FMIN */
#endif /* CCD_SINGLE */
#ifdef CCD_DOUBLE
typedef double ccd_real_t;
//# define CCD_EPS 1E-10
# define CCD_EPS DBL_EPSILON
# define CCD_REAL_MAX DBL_MAX
# define CCD_REAL(x) (x) /*!< form a constant */
# define CCD_SQRT(x) (sqrt(x)) /*!< square root */
# define CCD_FABS(x) (fabs(x)) /*!< absolute value */
# define CCD_FMAX(x, y) (fmax((x), (y))) /*!< maximum of two floats */
# ifndef CCD_FMIN
# define CCD_FMIN(x, y) (fmin((x), (y))) /*!< minimum of two floats */
# endif /* CCD_FMIN */
#endif /* CCD_DOUBLE */
#define CCD_ONE CCD_REAL(1.)
#define CCD_ZERO CCD_REAL(0.)
struct _ccd_vec3_t {
ccd_real_t v[3];
};
typedef struct _ccd_vec3_t ccd_vec3_t;
/**
* Holds origin (0,0,0) - this variable is meant to be read-only!
*/
CCD_EXPORT extern ccd_vec3_t *ccd_vec3_origin;
/**
* Array of points uniformly distributed on unit sphere.
*/
CCD_EXPORT extern ccd_vec3_t *ccd_points_on_sphere;
CCD_EXPORT extern size_t ccd_points_on_sphere_len;
/** Returns sign of value. */
_ccd_inline int ccdSign(ccd_real_t val);
/** Returns true if val is zero. **/
_ccd_inline int ccdIsZero(ccd_real_t val);
/** Returns true if a and b equal. **/
_ccd_inline int ccdEq(ccd_real_t a, ccd_real_t b);
#define CCD_VEC3_STATIC(x, y, z) \
{ { (x), (y), (z) } }
#define CCD_VEC3(name, x, y, z) \
ccd_vec3_t name = CCD_VEC3_STATIC((x), (y), (z))
_ccd_inline ccd_real_t ccdVec3X(const ccd_vec3_t *v);
_ccd_inline ccd_real_t ccdVec3Y(const ccd_vec3_t *v);
_ccd_inline ccd_real_t ccdVec3Z(const ccd_vec3_t *v);
/**
* Returns true if a and b equal.
*/
_ccd_inline int ccdVec3Eq(const ccd_vec3_t *a, const ccd_vec3_t *b);
/**
* Returns squared length of vector.
*/
_ccd_inline ccd_real_t ccdVec3Len2(const ccd_vec3_t *v);
/**
* Returns distance between a and b.
*/
_ccd_inline ccd_real_t ccdVec3Dist2(const ccd_vec3_t *a, const ccd_vec3_t *b);
_ccd_inline void ccdVec3Set(ccd_vec3_t *v, ccd_real_t x, ccd_real_t y, ccd_real_t z);
/**
* v = w
*/
_ccd_inline void ccdVec3Copy(ccd_vec3_t *v, const ccd_vec3_t *w);
/**
* Substracts coordinates of vector w from vector v. v = v - w
*/
_ccd_inline void ccdVec3Sub(ccd_vec3_t *v, const ccd_vec3_t *w);
/**
* Adds coordinates of vector w to vector v. v = v + w
*/
_ccd_inline void ccdVec3Add(ccd_vec3_t *v, const ccd_vec3_t *w);
/**
* d = v - w
*/
_ccd_inline void ccdVec3Sub2(ccd_vec3_t *d, const ccd_vec3_t *v, const ccd_vec3_t *w);
/**
* d = d * k;
*/
_ccd_inline void ccdVec3Scale(ccd_vec3_t *d, ccd_real_t k);
/**
* Normalizes given vector to unit length.
*/
_ccd_inline void ccdVec3Normalize(ccd_vec3_t *d);
/**
* Dot product of two vectors.
*/
_ccd_inline ccd_real_t ccdVec3Dot(const ccd_vec3_t *a, const ccd_vec3_t *b);
/**
* Cross product: d = a x b.
*/
_ccd_inline void ccdVec3Cross(ccd_vec3_t *d, const ccd_vec3_t *a, const ccd_vec3_t *b);
/**
* Returns distance^2 of point P to segment ab.
* If witness is non-NULL it is filled with coordinates of point from which
* was computed distance to point P.
*/
CCD_EXPORT ccd_real_t ccdVec3PointSegmentDist2(const ccd_vec3_t *P,
const ccd_vec3_t *a,
const ccd_vec3_t *b,
ccd_vec3_t *witness);
/**
* Returns distance^2 of point P from triangle formed by triplet a, b, c.
* If witness vector is provided it is filled with coordinates of point
* from which was computed distance to point P.
*/
CCD_EXPORT ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P,
const ccd_vec3_t *a,
const ccd_vec3_t *b,
const ccd_vec3_t *c,
ccd_vec3_t *witness);
/**** INLINES ****/
_ccd_inline int ccdSign(ccd_real_t val)
{
if (ccdIsZero(val)){
return 0;
}else if (val < CCD_ZERO){
return -1;
}
return 1;
}
_ccd_inline int ccdIsZero(ccd_real_t val)
{
return CCD_FABS(val) < CCD_EPS;
}
_ccd_inline int ccdEq(ccd_real_t _a, ccd_real_t _b)
{
ccd_real_t ab;
ccd_real_t a, b;
ab = CCD_FABS(_a - _b);
if (CCD_FABS(ab) < CCD_EPS)
return 1;
a = CCD_FABS(_a);
b = CCD_FABS(_b);
if (b > a){
return ab < CCD_EPS * b;
}else{
return ab < CCD_EPS * a;
}
}
_ccd_inline ccd_real_t ccdVec3X(const ccd_vec3_t *v)
{
return v->v[0];
}
_ccd_inline ccd_real_t ccdVec3Y(const ccd_vec3_t *v)
{
return v->v[1];
}
_ccd_inline ccd_real_t ccdVec3Z(const ccd_vec3_t *v)
{
return v->v[2];
}
_ccd_inline int ccdVec3Eq(const ccd_vec3_t *a, const ccd_vec3_t *b)
{
return ccdEq(ccdVec3X(a), ccdVec3X(b))
&& ccdEq(ccdVec3Y(a), ccdVec3Y(b))
&& ccdEq(ccdVec3Z(a), ccdVec3Z(b));
}
_ccd_inline ccd_real_t ccdVec3Len2(const ccd_vec3_t *v)
{
return ccdVec3Dot(v, v);
}
_ccd_inline ccd_real_t ccdVec3Dist2(const ccd_vec3_t *a, const ccd_vec3_t *b)
{
ccd_vec3_t ab;
ccdVec3Sub2(&ab, a, b);
return ccdVec3Len2(&ab);
}
_ccd_inline void ccdVec3Set(ccd_vec3_t *v, ccd_real_t x, ccd_real_t y, ccd_real_t z)
{
v->v[0] = x;
v->v[1] = y;
v->v[2] = z;
}
_ccd_inline void ccdVec3Copy(ccd_vec3_t *v, const ccd_vec3_t *w)
{
*v = *w;
}
_ccd_inline void ccdVec3Sub(ccd_vec3_t *v, const ccd_vec3_t *w)
{
v->v[0] -= w->v[0];
v->v[1] -= w->v[1];
v->v[2] -= w->v[2];
}
_ccd_inline void ccdVec3Sub2(ccd_vec3_t *d, const ccd_vec3_t *v, const ccd_vec3_t *w)
{
d->v[0] = v->v[0] - w->v[0];
d->v[1] = v->v[1] - w->v[1];
d->v[2] = v->v[2] - w->v[2];
}
_ccd_inline void ccdVec3Add(ccd_vec3_t *v, const ccd_vec3_t *w)
{
v->v[0] += w->v[0];
v->v[1] += w->v[1];
v->v[2] += w->v[2];
}
_ccd_inline void ccdVec3Scale(ccd_vec3_t *d, ccd_real_t k)
{
d->v[0] *= k;
d->v[1] *= k;
d->v[2] *= k;
}
_ccd_inline void ccdVec3Normalize(ccd_vec3_t *d)
{
ccd_real_t k = CCD_ONE / CCD_SQRT(ccdVec3Len2(d));
ccdVec3Scale(d, k);
}
_ccd_inline ccd_real_t ccdVec3Dot(const ccd_vec3_t *a, const ccd_vec3_t *b)
{
ccd_real_t dot;
dot = a->v[0] * b->v[0];
dot += a->v[1] * b->v[1];
dot += a->v[2] * b->v[2];
return dot;
}
_ccd_inline void ccdVec3Cross(ccd_vec3_t *d, const ccd_vec3_t *a, const ccd_vec3_t *b)
{
d->v[0] = (a->v[1] * b->v[2]) - (a->v[2] * b->v[1]);
d->v[1] = (a->v[2] * b->v[0]) - (a->v[0] * b->v[2]);
d->v[2] = (a->v[0] * b->v[1]) - (a->v[1] * b->v[0]);
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_VEC3_H__ */

@ -1,65 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_DBG_H__
#define __CCD_DBG_H__
/**
* Some macros which can be used for printing debug info to stderr if macro
* NDEBUG not defined.
*
* DBG_PROLOGUE can be specified as string and this string will be
* prepended to output text
*/
#ifndef NDEBUG
#include <stdio.h>
#ifndef DBG_PROLOGUE
# define DBG_PROLOGUE
#endif
# define DBG(format, ...) do { \
fprintf(stderr, DBG_PROLOGUE "%s :: " format "\n", __func__, ## __VA_ARGS__); \
fflush(stderr); \
} while (0)
# define DBG2(str) do { \
fprintf(stderr, DBG_PROLOGUE "%s :: " str "\n", __func__); \
fflush(stderr); \
} while (0)
# define DBG_VEC3(vec, prefix) do {\
fprintf(stderr, DBG_PROLOGUE "%s :: %s[%lf %lf %lf]\n", \
__func__, prefix, ccdVec3X(vec), ccdVec3Y(vec), ccdVec3Z(vec)); \
fflush(stderr); \
} while (0)
/*
# define DBG_VEC3(vec, prefix) do {\
fprintf(stderr, DBG_PROLOGUE "%s :: %s[%.20lf %.20lf %.20lf]\n", \
__func__, prefix, ccdVec3X(vec), ccdVec3Y(vec), ccdVec3Z(vec)); \
fflush(stderr); \
} while (0)
*/
#else
# define DBG(format, ...)
# define DBG2(str)
# define DBG_VEC3(v, prefix)
#endif
#endif /* __CCD_DBG_H__ */

@ -1,155 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_LIST_H__
#define __CCD_LIST_H__
#include <string.h>
#include <ccd/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct _ccd_list_t {
struct _ccd_list_t *next, *prev;
};
typedef struct _ccd_list_t ccd_list_t;
/**
* Get the struct for this entry.
* @ptr: the &ccd_list_t pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define ccdListEntry(ptr, type, member) \
ccd_container_of(ptr, type, member)
/**
* Iterates over list.
*/
#define ccdListForEach(list, item) \
for (item = (list)->next; \
_ccd_prefetch((item)->next), item != (list); \
item = (item)->next)
/**
* Iterates over list safe against remove of list entry
*/
#define ccdListForEachSafe(list, item, tmp) \
for (item = (list)->next, tmp = (item)->next; \
item != (list); \
item = tmp, tmp = (item)->next)
/**
* Iterates over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define ccdListForEachEntry(head, pos, postype, member) \
for (pos = ccdListEntry((head)->next, postype, member); \
_ccd_prefetch(pos->member.next), &pos->member != (head); \
pos = ccdListEntry(pos->member.next, postype, member))
/**
* Iterates over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define ccdListForEachEntrySafe(head, pos, postype, n, ntype, member) \
for (pos = ccdListEntry((head)->next, postype, member), \
n = ccdListEntry(pos->member.next, postype, member); \
&pos->member != (head); \
pos = n, n = ccdListEntry(n->member.next, ntype, member))
/**
* Initialize list.
*/
_ccd_inline void ccdListInit(ccd_list_t *l);
_ccd_inline ccd_list_t *ccdListNext(ccd_list_t *l);
_ccd_inline ccd_list_t *ccdListPrev(ccd_list_t *l);
/**
* Returns true if list is empty.
*/
_ccd_inline int ccdListEmpty(const ccd_list_t *head);
/**
* Appends item to end of the list l.
*/
_ccd_inline void ccdListAppend(ccd_list_t *l, ccd_list_t *item);
/**
* Removes item from list.
*/
_ccd_inline void ccdListDel(ccd_list_t *item);
///
/// INLINES:
///
_ccd_inline void ccdListInit(ccd_list_t *l)
{
l->next = l;
l->prev = l;
}
_ccd_inline ccd_list_t *ccdListNext(ccd_list_t *l)
{
return l->next;
}
_ccd_inline ccd_list_t *ccdListPrev(ccd_list_t *l)
{
return l->prev;
}
_ccd_inline int ccdListEmpty(const ccd_list_t *head)
{
return head->next == head;
}
_ccd_inline void ccdListAppend(ccd_list_t *l, ccd_list_t *new)
{
new->prev = l->prev;
new->next = l;
l->prev->next = new;
l->prev = new;
}
_ccd_inline void ccdListDel(ccd_list_t *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
item->next = item;
item->prev = item;
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_LIST_H__ */

@ -1,543 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010,2011 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#include <stdlib.h>
#include <ccd/ccd.h>
#include "simplex.h"
#include "dbg.h"
/** Finds origin (center) of Minkowski difference (actually it can be any
* interior point of Minkowski difference. */
_ccd_inline void findOrigin(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_support_t *center);
/** Discovers initial portal - that is tetrahedron that intersects with
* origin ray (ray from center of Minkowski diff to (0,0,0).
*
* Returns -1 if already recognized that origin is outside Minkowski
* portal.
* Returns 1 if origin lies on v1 of simplex (only v0 and v1 are present
* in simplex).
* Returns 2 if origin lies on v0-v1 segment.
* Returns 0 if portal was built.
*/
static int discoverPortal(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_simplex_t *portal);
/** Expands portal towards origin and determine if objects intersect.
* Already established portal must be given as argument.
* If intersection is found 0 is returned, -1 otherwise */
static int refinePortal(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_simplex_t *portal);
/** Finds penetration info by expanding provided portal. */
static void findPenetr(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_simplex_t *portal,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos);
/** Finds penetration info if origin lies on portal's v1 */
static void findPenetrTouch(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_simplex_t *portal,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos);
/** Find penetration info if origin lies on portal's segment v0-v1 */
static void findPenetrSegment(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_simplex_t *portal,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos);
/** Finds position vector from fully established portal */
static void findPos(const void *obj1, const void *obj2, const ccd_t *ccd,
const ccd_simplex_t *portal, ccd_vec3_t *pos);
/** Extends portal with new support point.
* Portal must have face v1-v2-v3 arranged to face outside portal. */
_ccd_inline void expandPortal(ccd_simplex_t *portal,
const ccd_support_t *v4);
/** Fill dir with direction outside portal. Portal's v1-v2-v3 face must be
* arranged in correct order! */
_ccd_inline void portalDir(const ccd_simplex_t *portal, ccd_vec3_t *dir);
/** Returns true if portal encapsules origin (0,0,0), dir is direction of
* v1-v2-v3 face. */
_ccd_inline int portalEncapsulesOrigin(const ccd_simplex_t *portal,
const ccd_vec3_t *dir);
/** Returns true if portal with new point v4 would reach specified
* tolerance (i.e. returns true if portal can _not_ significantly expand
* within Minkowski difference).
*
* v4 is candidate for new point in portal, dir is direction in which v4
* was obtained. */
_ccd_inline int portalReachTolerance(const ccd_simplex_t *portal,
const ccd_support_t *v4,
const ccd_vec3_t *dir,
const ccd_t *ccd);
/** Returns true if portal expanded by new point v4 could possibly contain
* origin, dir is direction in which v4 was obtained. */
_ccd_inline int portalCanEncapsuleOrigin(const ccd_simplex_t *portal,
const ccd_support_t *v4,
const ccd_vec3_t *dir);
int ccdMPRIntersect(const void *obj1, const void *obj2, const ccd_t *ccd)
{
ccd_simplex_t portal;
int res;
// Phase 1: Portal discovery - find portal that intersects with origin
// ray (ray from center of Minkowski diff to origin of coordinates)
res = discoverPortal(obj1, obj2, ccd, &portal);
if (res < 0)
return 0;
if (res > 0)
return 1;
// Phase 2: Portal refinement
res = refinePortal(obj1, obj2, ccd, &portal);
return (res == 0 ? 1 : 0);
}
int ccdMPRPenetration(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos)
{
ccd_simplex_t portal;
int res;
// Phase 1: Portal discovery
res = discoverPortal(obj1, obj2, ccd, &portal);
if (res < 0){
// Origin isn't inside portal - no collision.
return -1;
}else if (res == 1){
// Touching contact on portal's v1.
findPenetrTouch(obj1, obj2, ccd, &portal, depth, dir, pos);
}else if (res == 2){
// Origin lies on v0-v1 segment.
findPenetrSegment(obj1, obj2, ccd, &portal, depth, dir, pos);
}else if (res == 0){
// Phase 2: Portal refinement
res = refinePortal(obj1, obj2, ccd, &portal);
if (res < 0)
return -1;
// Phase 3. Penetration info
findPenetr(obj1, obj2, ccd, &portal, depth, dir, pos);
}
return 0;
}
_ccd_inline void findOrigin(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_support_t *center)
{
ccd->center1(obj1, &center->v1);
ccd->center2(obj2, &center->v2);
ccdVec3Sub2(&center->v, &center->v1, &center->v2);
}
static int discoverPortal(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_simplex_t *portal)
{
ccd_vec3_t dir, va, vb;
ccd_real_t dot;
int cont;
// vertex 0 is center of portal
findOrigin(obj1, obj2, ccd, ccdSimplexPointW(portal, 0));
ccdSimplexSetSize(portal, 1);
if (ccdVec3Eq(&ccdSimplexPoint(portal, 0)->v, ccd_vec3_origin)){
// Portal's center lies on origin (0,0,0) => we know that objects
// intersect but we would need to know penetration info.
// So move center little bit...
ccdVec3Set(&va, CCD_EPS * CCD_REAL(10.), CCD_ZERO, CCD_ZERO);
ccdVec3Add(&ccdSimplexPointW(portal, 0)->v, &va);
}
// vertex 1 = support in direction of origin
ccdVec3Copy(&dir, &ccdSimplexPoint(portal, 0)->v);
ccdVec3Scale(&dir, CCD_REAL(-1.));
ccdVec3Normalize(&dir);
__ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 1));
ccdSimplexSetSize(portal, 2);
// test if origin isn't outside of v1
dot = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, &dir);
if (ccdIsZero(dot) || dot < CCD_ZERO)
return -1;
// vertex 2
ccdVec3Cross(&dir, &ccdSimplexPoint(portal, 0)->v,
&ccdSimplexPoint(portal, 1)->v);
if (ccdIsZero(ccdVec3Len2(&dir))){
if (ccdVec3Eq(&ccdSimplexPoint(portal, 1)->v, ccd_vec3_origin)){
// origin lies on v1
return 1;
}else{
// origin lies on v0-v1 segment
return 2;
}
}
ccdVec3Normalize(&dir);
__ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 2));
dot = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, &dir);
if (ccdIsZero(dot) || dot < CCD_ZERO)
return -1;
ccdSimplexSetSize(portal, 3);
// vertex 3 direction
ccdVec3Sub2(&va, &ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 0)->v);
ccdVec3Sub2(&vb, &ccdSimplexPoint(portal, 2)->v,
&ccdSimplexPoint(portal, 0)->v);
ccdVec3Cross(&dir, &va, &vb);
ccdVec3Normalize(&dir);
// it is better to form portal faces to be oriented "outside" origin
dot = ccdVec3Dot(&dir, &ccdSimplexPoint(portal, 0)->v);
if (dot > CCD_ZERO){
ccdSimplexSwap(portal, 1, 2);
ccdVec3Scale(&dir, CCD_REAL(-1.));
}
while (ccdSimplexSize(portal) < 4){
__ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 3));
dot = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, &dir);
if (ccdIsZero(dot) || dot < CCD_ZERO)
return -1;
cont = 0;
// test if origin is outside (v1, v0, v3) - set v2 as v3 and
// continue
ccdVec3Cross(&va, &ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 3)->v);
dot = ccdVec3Dot(&va, &ccdSimplexPoint(portal, 0)->v);
if (dot < CCD_ZERO && !ccdIsZero(dot)){
ccdSimplexSet(portal, 2, ccdSimplexPoint(portal, 3));
cont = 1;
}
if (!cont){
// test if origin is outside (v3, v0, v2) - set v1 as v3 and
// continue
ccdVec3Cross(&va, &ccdSimplexPoint(portal, 3)->v,
&ccdSimplexPoint(portal, 2)->v);
dot = ccdVec3Dot(&va, &ccdSimplexPoint(portal, 0)->v);
if (dot < CCD_ZERO && !ccdIsZero(dot)){
ccdSimplexSet(portal, 1, ccdSimplexPoint(portal, 3));
cont = 1;
}
}
if (cont){
ccdVec3Sub2(&va, &ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 0)->v);
ccdVec3Sub2(&vb, &ccdSimplexPoint(portal, 2)->v,
&ccdSimplexPoint(portal, 0)->v);
ccdVec3Cross(&dir, &va, &vb);
ccdVec3Normalize(&dir);
}else{
ccdSimplexSetSize(portal, 4);
}
}
return 0;
}
static int refinePortal(const void *obj1, const void *obj2,
const ccd_t *ccd, ccd_simplex_t *portal)
{
ccd_vec3_t dir;
ccd_support_t v4;
while (1){
// compute direction outside the portal (from v0 throught v1,v2,v3
// face)
portalDir(portal, &dir);
// test if origin is inside the portal
if (portalEncapsulesOrigin(portal, &dir))
return 0;
// get next support point
__ccdSupport(obj1, obj2, &dir, ccd, &v4);
// test if v4 can expand portal to contain origin and if portal
// expanding doesn't reach given tolerance
if (!portalCanEncapsuleOrigin(portal, &v4, &dir)
|| portalReachTolerance(portal, &v4, &dir, ccd)){
return -1;
}
// v1-v2-v3 triangle must be rearranged to face outside Minkowski
// difference (direction from v0).
expandPortal(portal, &v4);
}
return -1;
}
static void findPenetr(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_simplex_t *portal,
ccd_real_t *depth, ccd_vec3_t *pdir, ccd_vec3_t *pos)
{
ccd_vec3_t dir;
ccd_support_t v4;
unsigned long iterations;
iterations = 0UL;
while (1){
// compute portal direction and obtain next support point
portalDir(portal, &dir);
__ccdSupport(obj1, obj2, &dir, ccd, &v4);
// reached tolerance -> find penetration info
if (portalReachTolerance(portal, &v4, &dir, ccd)
|| iterations > ccd->max_iterations){
*depth = ccdVec3PointTriDist2(ccd_vec3_origin,
&ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 2)->v,
&ccdSimplexPoint(portal, 3)->v,
pdir);
*depth = CCD_SQRT(*depth);
if (ccdIsZero(*depth)){
// If depth is zero, then we have a touching contact.
// So following findPenetrTouch(), we assign zero to
// the direction vector (it can actually be anything
// according to the decription of ccdMPRPenetration
// function).
ccdVec3Copy(pdir, ccd_vec3_origin);
}else{
ccdVec3Normalize(pdir);
}
// barycentric coordinates:
findPos(obj1, obj2, ccd, portal, pos);
return;
}
expandPortal(portal, &v4);
iterations++;
}
}
static void findPenetrTouch(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_simplex_t *portal,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos)
{
// Touching contact on portal's v1 - so depth is zero and direction
// is unimportant and pos can be guessed
*depth = CCD_REAL(0.);
ccdVec3Copy(dir, ccd_vec3_origin);
ccdVec3Copy(pos, &ccdSimplexPoint(portal, 1)->v1);
ccdVec3Add(pos, &ccdSimplexPoint(portal, 1)->v2);
ccdVec3Scale(pos, 0.5);
}
static void findPenetrSegment(const void *obj1, const void *obj2, const ccd_t *ccd,
ccd_simplex_t *portal,
ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos)
{
/*
ccd_vec3_t vec;
ccd_real_t k;
*/
// Origin lies on v0-v1 segment.
// Depth is distance to v1, direction also and position must be
// computed
ccdVec3Copy(pos, &ccdSimplexPoint(portal, 1)->v1);
ccdVec3Add(pos, &ccdSimplexPoint(portal, 1)->v2);
ccdVec3Scale(pos, CCD_REAL(0.5));
/*
ccdVec3Sub2(&vec, &ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 0)->v);
k = CCD_SQRT(ccdVec3Len2(&ccdSimplexPoint(portal, 0)->v));
k /= CCD_SQRT(ccdVec3Len2(&vec));
ccdVec3Scale(&vec, -k);
ccdVec3Add(pos, &vec);
*/
ccdVec3Copy(dir, &ccdSimplexPoint(portal, 1)->v);
*depth = CCD_SQRT(ccdVec3Len2(dir));
ccdVec3Normalize(dir);
}
static void findPos(const void *obj1, const void *obj2, const ccd_t *ccd,
const ccd_simplex_t *portal, ccd_vec3_t *pos)
{
ccd_vec3_t dir;
size_t i;
ccd_real_t b[4], sum, inv;
ccd_vec3_t vec, p1, p2;
portalDir(portal, &dir);
// use barycentric coordinates of tetrahedron to find origin
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 2)->v);
b[0] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 3)->v);
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 3)->v,
&ccdSimplexPoint(portal, 2)->v);
b[1] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 0)->v);
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 0)->v,
&ccdSimplexPoint(portal, 1)->v);
b[2] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 3)->v);
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 2)->v,
&ccdSimplexPoint(portal, 1)->v);
b[3] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 0)->v);
sum = b[0] + b[1] + b[2] + b[3];
if (ccdIsZero(sum) || sum < CCD_ZERO){
b[0] = CCD_REAL(0.);
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 2)->v,
&ccdSimplexPoint(portal, 3)->v);
b[1] = ccdVec3Dot(&vec, &dir);
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 3)->v,
&ccdSimplexPoint(portal, 1)->v);
b[2] = ccdVec3Dot(&vec, &dir);
ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 1)->v,
&ccdSimplexPoint(portal, 2)->v);
b[3] = ccdVec3Dot(&vec, &dir);
sum = b[1] + b[2] + b[3];
}
inv = CCD_REAL(1.) / sum;
ccdVec3Copy(&p1, ccd_vec3_origin);
ccdVec3Copy(&p2, ccd_vec3_origin);
for (i = 0; i < 4; i++){
ccdVec3Copy(&vec, &ccdSimplexPoint(portal, i)->v1);
ccdVec3Scale(&vec, b[i]);
ccdVec3Add(&p1, &vec);
ccdVec3Copy(&vec, &ccdSimplexPoint(portal, i)->v2);
ccdVec3Scale(&vec, b[i]);
ccdVec3Add(&p2, &vec);
}
ccdVec3Scale(&p1, inv);
ccdVec3Scale(&p2, inv);
ccdVec3Copy(pos, &p1);
ccdVec3Add(pos, &p2);
ccdVec3Scale(pos, 0.5);
}
_ccd_inline void expandPortal(ccd_simplex_t *portal,
const ccd_support_t *v4)
{
ccd_real_t dot;
ccd_vec3_t v4v0;
ccdVec3Cross(&v4v0, &v4->v, &ccdSimplexPoint(portal, 0)->v);
dot = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, &v4v0);
if (dot > CCD_ZERO){
dot = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, &v4v0);
if (dot > CCD_ZERO){
ccdSimplexSet(portal, 1, v4);
}else{
ccdSimplexSet(portal, 3, v4);
}
}else{
dot = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, &v4v0);
if (dot > CCD_ZERO){
ccdSimplexSet(portal, 2, v4);
}else{
ccdSimplexSet(portal, 1, v4);
}
}
}
_ccd_inline void portalDir(const ccd_simplex_t *portal, ccd_vec3_t *dir)
{
ccd_vec3_t v2v1, v3v1;
ccdVec3Sub2(&v2v1, &ccdSimplexPoint(portal, 2)->v,
&ccdSimplexPoint(portal, 1)->v);
ccdVec3Sub2(&v3v1, &ccdSimplexPoint(portal, 3)->v,
&ccdSimplexPoint(portal, 1)->v);
ccdVec3Cross(dir, &v2v1, &v3v1);
ccdVec3Normalize(dir);
}
_ccd_inline int portalEncapsulesOrigin(const ccd_simplex_t *portal,
const ccd_vec3_t *dir)
{
ccd_real_t dot;
dot = ccdVec3Dot(dir, &ccdSimplexPoint(portal, 1)->v);
return ccdIsZero(dot) || dot > CCD_ZERO;
}
_ccd_inline int portalReachTolerance(const ccd_simplex_t *portal,
const ccd_support_t *v4,
const ccd_vec3_t *dir,
const ccd_t *ccd)
{
ccd_real_t dv1, dv2, dv3, dv4;
ccd_real_t dot1, dot2, dot3;
// find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}
dv1 = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, dir);
dv2 = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, dir);
dv3 = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, dir);
dv4 = ccdVec3Dot(&v4->v, dir);
dot1 = dv4 - dv1;
dot2 = dv4 - dv2;
dot3 = dv4 - dv3;
dot1 = CCD_FMIN(dot1, dot2);
dot1 = CCD_FMIN(dot1, dot3);
return ccdEq(dot1, ccd->mpr_tolerance) || dot1 < ccd->mpr_tolerance;
}
_ccd_inline int portalCanEncapsuleOrigin(const ccd_simplex_t *portal,
const ccd_support_t *v4,
const ccd_vec3_t *dir)
{
ccd_real_t dot;
dot = ccdVec3Dot(&v4->v, dir);
return ccdIsZero(dot) || dot > CCD_ZERO;
}

@ -1,298 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#include <stdio.h>
#include <float.h>
#include "polytope.h"
#include "alloc.h"
_ccd_inline void _ccdPtNearestUpdate(ccd_pt_t *pt, ccd_pt_el_t *el)
{
if (ccdEq(pt->nearest_dist, el->dist)){
if (el->type < pt->nearest_type){
pt->nearest = el;
pt->nearest_dist = el->dist;
pt->nearest_type = el->type;
}
}else if (el->dist < pt->nearest_dist){
pt->nearest = el;
pt->nearest_dist = el->dist;
pt->nearest_type = el->type;
}
}
static void _ccdPtNearestRenew(ccd_pt_t *pt)
{
ccd_pt_vertex_t *v;
ccd_pt_edge_t *e;
ccd_pt_face_t *f;
pt->nearest_dist = CCD_REAL_MAX;
pt->nearest_type = 3;
pt->nearest = NULL;
ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){
_ccdPtNearestUpdate(pt, (ccd_pt_el_t *)v);
}
ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){
_ccdPtNearestUpdate(pt, (ccd_pt_el_t *)e);
}
ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){
_ccdPtNearestUpdate(pt, (ccd_pt_el_t *)f);
}
}
void ccdPtInit(ccd_pt_t *pt)
{
ccdListInit(&pt->vertices);
ccdListInit(&pt->edges);
ccdListInit(&pt->faces);
pt->nearest = NULL;
pt->nearest_dist = CCD_REAL_MAX;
pt->nearest_type = 3;
}
void ccdPtDestroy(ccd_pt_t *pt)
{
ccd_pt_face_t *f, *f2;
ccd_pt_edge_t *e, *e2;
ccd_pt_vertex_t *v, *v2;
// first delete all faces
ccdListForEachEntrySafe(&pt->faces, f, ccd_pt_face_t, f2, ccd_pt_face_t, list){
ccdPtDelFace(pt, f);
}
// delete all edges
ccdListForEachEntrySafe(&pt->edges, e, ccd_pt_edge_t, e2, ccd_pt_edge_t, list){
ccdPtDelEdge(pt, e);
}
// delete all vertices
ccdListForEachEntrySafe(&pt->vertices, v, ccd_pt_vertex_t, v2, ccd_pt_vertex_t, list){
ccdPtDelVertex(pt, v);
}
}
ccd_pt_vertex_t *ccdPtAddVertex(ccd_pt_t *pt, const ccd_support_t *v)
{
ccd_pt_vertex_t *vert;
vert = CCD_ALLOC(ccd_pt_vertex_t);
if (vert == NULL)
return NULL;
vert->type = CCD_PT_VERTEX;
ccdSupportCopy(&vert->v, v);
vert->dist = ccdVec3Len2(&vert->v.v);
ccdVec3Copy(&vert->witness, &vert->v.v);
ccdListInit(&vert->edges);
// add vertex to list
ccdListAppend(&pt->vertices, &vert->list);
// update position in .nearest array
_ccdPtNearestUpdate(pt, (ccd_pt_el_t *)vert);
return vert;
}
ccd_pt_edge_t *ccdPtAddEdge(ccd_pt_t *pt, ccd_pt_vertex_t *v1,
ccd_pt_vertex_t *v2)
{
const ccd_vec3_t *a, *b;
ccd_pt_edge_t *edge;
if (v1 == NULL || v2 == NULL)
return NULL;
edge = CCD_ALLOC(ccd_pt_edge_t);
if (edge == NULL)
return NULL;
edge->type = CCD_PT_EDGE;
edge->vertex[0] = v1;
edge->vertex[1] = v2;
edge->faces[0] = edge->faces[1] = NULL;
a = &edge->vertex[0]->v.v;
b = &edge->vertex[1]->v.v;
edge->dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, a, b, &edge->witness);
ccdListAppend(&edge->vertex[0]->edges, &edge->vertex_list[0]);
ccdListAppend(&edge->vertex[1]->edges, &edge->vertex_list[1]);
ccdListAppend(&pt->edges, &edge->list);
// update position in .nearest array
_ccdPtNearestUpdate(pt, (ccd_pt_el_t *)edge);
return edge;
}
ccd_pt_face_t *ccdPtAddFace(ccd_pt_t *pt, ccd_pt_edge_t *e1,
ccd_pt_edge_t *e2,
ccd_pt_edge_t *e3)
{
const ccd_vec3_t *a, *b, *c;
ccd_pt_face_t *face;
ccd_pt_edge_t *e;
size_t i;
if (e1 == NULL || e2 == NULL || e3 == NULL)
return NULL;
face = CCD_ALLOC(ccd_pt_face_t);
if (face == NULL)
return NULL;
face->type = CCD_PT_FACE;
face->edge[0] = e1;
face->edge[1] = e2;
face->edge[2] = e3;
// obtain triplet of vertices
a = &face->edge[0]->vertex[0]->v.v;
b = &face->edge[0]->vertex[1]->v.v;
e = face->edge[1];
if (e->vertex[0] != face->edge[0]->vertex[0]
&& e->vertex[0] != face->edge[0]->vertex[1]){
c = &e->vertex[0]->v.v;
}else{
c = &e->vertex[1]->v.v;
}
face->dist = ccdVec3PointTriDist2(ccd_vec3_origin, a, b, c, &face->witness);
for (i = 0; i < 3; i++){
if (face->edge[i]->faces[0] == NULL){
face->edge[i]->faces[0] = face;
}else{
face->edge[i]->faces[1] = face;
}
}
ccdListAppend(&pt->faces, &face->list);
// update position in .nearest array
_ccdPtNearestUpdate(pt, (ccd_pt_el_t *)face);
return face;
}
void ccdPtRecomputeDistances(ccd_pt_t *pt)
{
ccd_pt_vertex_t *v;
ccd_pt_edge_t *e;
ccd_pt_face_t *f;
const ccd_vec3_t *a, *b, *c;
ccd_real_t dist;
ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){
dist = ccdVec3Len2(&v->v.v);
v->dist = dist;
ccdVec3Copy(&v->witness, &v->v.v);
}
ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){
a = &e->vertex[0]->v.v;
b = &e->vertex[1]->v.v;
dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, a, b, &e->witness);
e->dist = dist;
}
ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){
// obtain triplet of vertices
a = &f->edge[0]->vertex[0]->v.v;
b = &f->edge[0]->vertex[1]->v.v;
e = f->edge[1];
if (e->vertex[0] != f->edge[0]->vertex[0]
&& e->vertex[0] != f->edge[0]->vertex[1]){
c = &e->vertex[0]->v.v;
}else{
c = &e->vertex[1]->v.v;
}
dist = ccdVec3PointTriDist2(ccd_vec3_origin, a, b, c, &f->witness);
f->dist = dist;
}
}
ccd_pt_el_t *ccdPtNearest(ccd_pt_t *pt)
{
if (!pt->nearest){
_ccdPtNearestRenew(pt);
}
return pt->nearest;
}
void ccdPtDumpSVT(ccd_pt_t *pt, const char *fn)
{
FILE *fout;
fout = fopen(fn, "a");
if (fout == NULL)
return;
ccdPtDumpSVT2(pt, fout);
fclose(fout);
}
void ccdPtDumpSVT2(ccd_pt_t *pt, FILE *fout)
{
ccd_pt_vertex_t *v, *a, *b, *c;
ccd_pt_edge_t *e;
ccd_pt_face_t *f;
size_t i;
fprintf(fout, "-----\n");
fprintf(fout, "Points:\n");
i = 0;
ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){
v->id = i++;
fprintf(fout, "%lf %lf %lf\n",
ccdVec3X(&v->v.v), ccdVec3Y(&v->v.v), ccdVec3Z(&v->v.v));
}
fprintf(fout, "Edges:\n");
ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){
fprintf(fout, "%d %d\n", e->vertex[0]->id, e->vertex[1]->id);
}
fprintf(fout, "Faces:\n");
ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){
a = f->edge[0]->vertex[0];
b = f->edge[0]->vertex[1];
c = f->edge[1]->vertex[0];
if (c == a || c == b){
c = f->edge[1]->vertex[1];
}
fprintf(fout, "%d %d %d\n", a->id, b->id, c->id);
}
}

@ -1,322 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_POLYTOPE_H__
#define __CCD_POLYTOPE_H__
#include <stdlib.h>
#include <stdio.h>
#include "support.h"
#include "list.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define CCD_PT_VERTEX 1
#define CCD_PT_EDGE 2
#define CCD_PT_FACE 3
#define __CCD_PT_EL \
int type; /*! type of element */ \
ccd_real_t dist; /*! distance from origin */ \
ccd_vec3_t witness; /*! witness point of projection of origin */ \
ccd_list_t list; /*! list of elements of same type */
/**
* General polytope element.
* Could be vertex, edge or triangle.
*/
struct _ccd_pt_el_t {
__CCD_PT_EL
};
typedef struct _ccd_pt_el_t ccd_pt_el_t;
struct _ccd_pt_edge_t;
struct _ccd_pt_face_t;
/**
* Polytope's vertex.
*/
struct _ccd_pt_vertex_t {
__CCD_PT_EL
int id;
ccd_support_t v;
ccd_list_t edges; //!< List of edges
};
typedef struct _ccd_pt_vertex_t ccd_pt_vertex_t;
/**
* Polytope's edge.
*/
struct _ccd_pt_edge_t {
__CCD_PT_EL
ccd_pt_vertex_t *vertex[2]; //!< Reference to vertices
struct _ccd_pt_face_t *faces[2]; //!< Reference to faces
ccd_list_t vertex_list[2]; //!< List items in vertices' lists
};
typedef struct _ccd_pt_edge_t ccd_pt_edge_t;
/**
* Polytope's triangle faces.
*/
struct _ccd_pt_face_t {
__CCD_PT_EL
ccd_pt_edge_t *edge[3]; //!< Reference to surrounding edges
};
typedef struct _ccd_pt_face_t ccd_pt_face_t;
/**
* Struct containing polytope.
*/
struct _ccd_pt_t {
ccd_list_t vertices; //!< List of vertices
ccd_list_t edges; //!< List of edges
ccd_list_t faces; //!< List of faces
ccd_pt_el_t *nearest;
ccd_real_t nearest_dist;
int nearest_type;
};
typedef struct _ccd_pt_t ccd_pt_t;
CCD_EXPORT void ccdPtInit(ccd_pt_t *pt);
CCD_EXPORT void ccdPtDestroy(ccd_pt_t *pt);
/**
* Returns vertices surrounding given triangle face.
*/
_ccd_inline void ccdPtFaceVec3(const ccd_pt_face_t *face,
ccd_vec3_t **a,
ccd_vec3_t **b,
ccd_vec3_t **c);
_ccd_inline void ccdPtFaceVertices(const ccd_pt_face_t *face,
ccd_pt_vertex_t **a,
ccd_pt_vertex_t **b,
ccd_pt_vertex_t **c);
_ccd_inline void ccdPtFaceEdges(const ccd_pt_face_t *f,
ccd_pt_edge_t **a,
ccd_pt_edge_t **b,
ccd_pt_edge_t **c);
_ccd_inline void ccdPtEdgeVec3(const ccd_pt_edge_t *e,
ccd_vec3_t **a,
ccd_vec3_t **b);
_ccd_inline void ccdPtEdgeVertices(const ccd_pt_edge_t *e,
ccd_pt_vertex_t **a,
ccd_pt_vertex_t **b);
_ccd_inline void ccdPtEdgeFaces(const ccd_pt_edge_t *e,
ccd_pt_face_t **f1,
ccd_pt_face_t **f2);
/**
* Adds vertex to polytope and returns pointer to newly created vertex.
*/
CCD_EXPORT ccd_pt_vertex_t *ccdPtAddVertex(ccd_pt_t *pt, const ccd_support_t *v);
_ccd_inline ccd_pt_vertex_t *ccdPtAddVertexCoords(ccd_pt_t *pt,
ccd_real_t x, ccd_real_t y, ccd_real_t z);
/**
* Adds edge to polytope.
*/
CCD_EXPORT ccd_pt_edge_t *ccdPtAddEdge(ccd_pt_t *pt, ccd_pt_vertex_t *v1,
ccd_pt_vertex_t *v2);
/**
* Adds face to polytope.
*/
CCD_EXPORT ccd_pt_face_t *ccdPtAddFace(ccd_pt_t *pt, ccd_pt_edge_t *e1,
ccd_pt_edge_t *e2,
ccd_pt_edge_t *e3);
/**
* Deletes vertex from polytope.
* Returns 0 on success, -1 otherwise.
*/
_ccd_inline int ccdPtDelVertex(ccd_pt_t *pt, ccd_pt_vertex_t *);
_ccd_inline int ccdPtDelEdge(ccd_pt_t *pt, ccd_pt_edge_t *);
_ccd_inline int ccdPtDelFace(ccd_pt_t *pt, ccd_pt_face_t *);
/**
* Recompute distances from origin for all elements in pt.
*/
CCD_EXPORT void ccdPtRecomputeDistances(ccd_pt_t *pt);
/**
* Returns nearest element to origin.
*/
CCD_EXPORT ccd_pt_el_t *ccdPtNearest(ccd_pt_t *pt);
CCD_EXPORT void ccdPtDumpSVT(ccd_pt_t *pt, const char *fn);
CCD_EXPORT void ccdPtDumpSVT2(ccd_pt_t *pt, FILE *);
/**** INLINES ****/
_ccd_inline ccd_pt_vertex_t *ccdPtAddVertexCoords(ccd_pt_t *pt,
ccd_real_t x, ccd_real_t y, ccd_real_t z)
{
ccd_support_t s;
ccdVec3Set(&s.v, x, y, z);
return ccdPtAddVertex(pt, &s);
}
_ccd_inline int ccdPtDelVertex(ccd_pt_t *pt, ccd_pt_vertex_t *v)
{
// test if any edge is connected to this vertex
if (!ccdListEmpty(&v->edges))
return -1;
// delete vertex from main list
ccdListDel(&v->list);
if ((void *)pt->nearest == (void *)v){
pt->nearest = NULL;
}
free(v);
return 0;
}
_ccd_inline int ccdPtDelEdge(ccd_pt_t *pt, ccd_pt_edge_t *e)
{
// text if any face is connected to this edge (faces[] is always
// aligned to lower indices)
if (e->faces[0] != NULL)
return -1;
// disconnect edge from lists of edges in vertex struct
ccdListDel(&e->vertex_list[0]);
ccdListDel(&e->vertex_list[1]);
// disconnect edge from main list
ccdListDel(&e->list);
if ((void *)pt->nearest == (void *)e){
pt->nearest = NULL;
}
free(e);
return 0;
}
_ccd_inline int ccdPtDelFace(ccd_pt_t *pt, ccd_pt_face_t *f)
{
ccd_pt_edge_t *e;
size_t i;
// remove face from edges' recerence lists
for (i = 0; i < 3; i++){
e = f->edge[i];
if (e->faces[0] == f){
e->faces[0] = e->faces[1];
}
e->faces[1] = NULL;
}
// remove face from list of all faces
ccdListDel(&f->list);
if ((void *)pt->nearest == (void *)f){
pt->nearest = NULL;
}
free(f);
return 0;
}
_ccd_inline void ccdPtFaceVec3(const ccd_pt_face_t *face,
ccd_vec3_t **a,
ccd_vec3_t **b,
ccd_vec3_t **c)
{
*a = &face->edge[0]->vertex[0]->v.v;
*b = &face->edge[0]->vertex[1]->v.v;
if (face->edge[1]->vertex[0] != face->edge[0]->vertex[0]
&& face->edge[1]->vertex[0] != face->edge[0]->vertex[1]){
*c = &face->edge[1]->vertex[0]->v.v;
}else{
*c = &face->edge[1]->vertex[1]->v.v;
}
}
_ccd_inline void ccdPtFaceVertices(const ccd_pt_face_t *face,
ccd_pt_vertex_t **a,
ccd_pt_vertex_t **b,
ccd_pt_vertex_t **c)
{
*a = face->edge[0]->vertex[0];
*b = face->edge[0]->vertex[1];
if (face->edge[1]->vertex[0] != face->edge[0]->vertex[0]
&& face->edge[1]->vertex[0] != face->edge[0]->vertex[1]){
*c = face->edge[1]->vertex[0];
}else{
*c = face->edge[1]->vertex[1];
}
}
_ccd_inline void ccdPtFaceEdges(const ccd_pt_face_t *f,
ccd_pt_edge_t **a,
ccd_pt_edge_t **b,
ccd_pt_edge_t **c)
{
*a = f->edge[0];
*b = f->edge[1];
*c = f->edge[2];
}
_ccd_inline void ccdPtEdgeVec3(const ccd_pt_edge_t *e,
ccd_vec3_t **a,
ccd_vec3_t **b)
{
*a = &e->vertex[0]->v.v;
*b = &e->vertex[1]->v.v;
}
_ccd_inline void ccdPtEdgeVertices(const ccd_pt_edge_t *e,
ccd_pt_vertex_t **a,
ccd_pt_vertex_t **b)
{
*a = e->vertex[0];
*b = e->vertex[1];
}
_ccd_inline void ccdPtEdgeFaces(const ccd_pt_edge_t *e,
ccd_pt_face_t **f1,
ccd_pt_face_t **f2)
{
*f1 = e->faces[0];
*f2 = e->faces[1];
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_POLYTOPE_H__ */

@ -1,104 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_SIMPLEX_H__
#define __CCD_SIMPLEX_H__
#include <ccd/compiler.h>
#include "support.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct _ccd_simplex_t {
ccd_support_t ps[4];
int last; //!< index of last added point
};
typedef struct _ccd_simplex_t ccd_simplex_t;
_ccd_inline void ccdSimplexInit(ccd_simplex_t *s);
_ccd_inline int ccdSimplexSize(const ccd_simplex_t *s);
_ccd_inline const ccd_support_t *ccdSimplexLast(const ccd_simplex_t *s);
_ccd_inline const ccd_support_t *ccdSimplexPoint(const ccd_simplex_t *s, int idx);
_ccd_inline ccd_support_t *ccdSimplexPointW(ccd_simplex_t *s, int idx);
_ccd_inline void ccdSimplexAdd(ccd_simplex_t *s, const ccd_support_t *v);
_ccd_inline void ccdSimplexSet(ccd_simplex_t *s, size_t pos, const ccd_support_t *a);
_ccd_inline void ccdSimplexSetSize(ccd_simplex_t *s, int size);
_ccd_inline void ccdSimplexSwap(ccd_simplex_t *s, size_t pos1, size_t pos2);
/**** INLINES ****/
_ccd_inline void ccdSimplexInit(ccd_simplex_t *s)
{
s->last = -1;
}
_ccd_inline int ccdSimplexSize(const ccd_simplex_t *s)
{
return s->last + 1;
}
_ccd_inline const ccd_support_t *ccdSimplexLast(const ccd_simplex_t *s)
{
return ccdSimplexPoint(s, s->last);
}
_ccd_inline const ccd_support_t *ccdSimplexPoint(const ccd_simplex_t *s, int idx)
{
// here is no check on boundaries
return &s->ps[idx];
}
_ccd_inline ccd_support_t *ccdSimplexPointW(ccd_simplex_t *s, int idx)
{
return &s->ps[idx];
}
_ccd_inline void ccdSimplexAdd(ccd_simplex_t *s, const ccd_support_t *v)
{
// here is no check on boundaries in sake of speed
++s->last;
ccdSupportCopy(s->ps + s->last, v);
}
_ccd_inline void ccdSimplexSet(ccd_simplex_t *s, size_t pos, const ccd_support_t *a)
{
ccdSupportCopy(s->ps + pos, a);
}
_ccd_inline void ccdSimplexSetSize(ccd_simplex_t *s, int size)
{
s->last = size - 1;
}
_ccd_inline void ccdSimplexSwap(ccd_simplex_t *s, size_t pos1, size_t pos2)
{
ccd_support_t supp;
ccdSupportCopy(&supp, &s->ps[pos1]);
ccdSupportCopy(&s->ps[pos1], &s->ps[pos2]);
ccdSupportCopy(&s->ps[pos2], &supp);
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_SIMPLEX_H__ */

@ -1,34 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#include "support.h"
void __ccdSupport(const void *obj1, const void *obj2,
const ccd_vec3_t *_dir, const ccd_t *ccd,
ccd_support_t *supp)
{
ccd_vec3_t dir;
ccdVec3Copy(&dir, _dir);
ccd->support1(obj1, &dir, &supp->v1);
ccdVec3Scale(&dir, -CCD_ONE);
ccd->support2(obj2, &dir, &supp->v2);
ccdVec3Sub2(&supp->v, &supp->v1, &supp->v2);
}

@ -1,55 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#ifndef __CCD_SUPPORT_H__
#define __CCD_SUPPORT_H__
#include <ccd/ccd.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct _ccd_support_t {
ccd_vec3_t v; //!< Support point in minkowski sum
ccd_vec3_t v1; //!< Support point in obj1
ccd_vec3_t v2; //!< Support point in obj2
};
typedef struct _ccd_support_t ccd_support_t;
_ccd_inline void ccdSupportCopy(ccd_support_t *, const ccd_support_t *s);
/**
* Computes support point of obj1 and obj2 in direction dir.
* Support point is returned via supp.
*/
CCD_EXPORT void __ccdSupport(const void *obj1, const void *obj2,
const ccd_vec3_t *dir, const ccd_t *ccd,
ccd_support_t *supp);
/**** INLINES ****/
_ccd_inline void ccdSupportCopy(ccd_support_t *d, const ccd_support_t *s)
{
*d = *s;
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* __CCD_SUPPORT_H__ */

@ -1,217 +0,0 @@
/***
* libccd
* ---------------------------------
* Copyright (c)2010 Daniel Fiser <danfis@danfis.cz>
*
*
* This file is part of libccd.
*
* Distributed under the OSI-approved BSD License (the "License");
* see accompanying file BDS-LICENSE for details or see
* <http://www.opensource.org/licenses/bsd-license.php>.
*
* This software is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the License for more information.
*/
#include <stdio.h>
#include <ccd/vec3.h>
#include "dbg.h"
static CCD_VEC3(__ccd_vec3_origin, CCD_ZERO, CCD_ZERO, CCD_ZERO);
ccd_vec3_t *ccd_vec3_origin = &__ccd_vec3_origin;
static ccd_vec3_t points_on_sphere[] = {
CCD_VEC3_STATIC(CCD_REAL( 0.000000), CCD_REAL(-0.000000), CCD_REAL(-1.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.723608), CCD_REAL(-0.525725), CCD_REAL(-0.447219)),
CCD_VEC3_STATIC(CCD_REAL(-0.276388), CCD_REAL(-0.850649), CCD_REAL(-0.447219)),
CCD_VEC3_STATIC(CCD_REAL(-0.894426), CCD_REAL(-0.000000), CCD_REAL(-0.447216)),
CCD_VEC3_STATIC(CCD_REAL(-0.276388), CCD_REAL( 0.850649), CCD_REAL(-0.447220)),
CCD_VEC3_STATIC(CCD_REAL( 0.723608), CCD_REAL( 0.525725), CCD_REAL(-0.447219)),
CCD_VEC3_STATIC(CCD_REAL( 0.276388), CCD_REAL(-0.850649), CCD_REAL( 0.447220)),
CCD_VEC3_STATIC(CCD_REAL(-0.723608), CCD_REAL(-0.525725), CCD_REAL( 0.447219)),
CCD_VEC3_STATIC(CCD_REAL(-0.723608), CCD_REAL( 0.525725), CCD_REAL( 0.447219)),
CCD_VEC3_STATIC(CCD_REAL( 0.276388), CCD_REAL( 0.850649), CCD_REAL( 0.447219)),
CCD_VEC3_STATIC(CCD_REAL( 0.894426), CCD_REAL( 0.000000), CCD_REAL( 0.447216)),
CCD_VEC3_STATIC(CCD_REAL(-0.000000), CCD_REAL( 0.000000), CCD_REAL( 1.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.425323), CCD_REAL(-0.309011), CCD_REAL(-0.850654)),
CCD_VEC3_STATIC(CCD_REAL(-0.162456), CCD_REAL(-0.499995), CCD_REAL(-0.850654)),
CCD_VEC3_STATIC(CCD_REAL( 0.262869), CCD_REAL(-0.809012), CCD_REAL(-0.525738)),
CCD_VEC3_STATIC(CCD_REAL( 0.425323), CCD_REAL( 0.309011), CCD_REAL(-0.850654)),
CCD_VEC3_STATIC(CCD_REAL( 0.850648), CCD_REAL(-0.000000), CCD_REAL(-0.525736)),
CCD_VEC3_STATIC(CCD_REAL(-0.525730), CCD_REAL(-0.000000), CCD_REAL(-0.850652)),
CCD_VEC3_STATIC(CCD_REAL(-0.688190), CCD_REAL(-0.499997), CCD_REAL(-0.525736)),
CCD_VEC3_STATIC(CCD_REAL(-0.162456), CCD_REAL( 0.499995), CCD_REAL(-0.850654)),
CCD_VEC3_STATIC(CCD_REAL(-0.688190), CCD_REAL( 0.499997), CCD_REAL(-0.525736)),
CCD_VEC3_STATIC(CCD_REAL( 0.262869), CCD_REAL( 0.809012), CCD_REAL(-0.525738)),
CCD_VEC3_STATIC(CCD_REAL( 0.951058), CCD_REAL( 0.309013), CCD_REAL( 0.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.951058), CCD_REAL(-0.309013), CCD_REAL( 0.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.587786), CCD_REAL(-0.809017), CCD_REAL( 0.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.000000), CCD_REAL(-1.000000), CCD_REAL( 0.000000)),
CCD_VEC3_STATIC(CCD_REAL(-0.587786), CCD_REAL(-0.809017), CCD_REAL( 0.000000)),
CCD_VEC3_STATIC(CCD_REAL(-0.951058), CCD_REAL(-0.309013), CCD_REAL(-0.000000)),
CCD_VEC3_STATIC(CCD_REAL(-0.951058), CCD_REAL( 0.309013), CCD_REAL(-0.000000)),
CCD_VEC3_STATIC(CCD_REAL(-0.587786), CCD_REAL( 0.809017), CCD_REAL(-0.000000)),
CCD_VEC3_STATIC(CCD_REAL(-0.000000), CCD_REAL( 1.000000), CCD_REAL(-0.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.587786), CCD_REAL( 0.809017), CCD_REAL(-0.000000)),
CCD_VEC3_STATIC(CCD_REAL( 0.688190), CCD_REAL(-0.499997), CCD_REAL( 0.525736)),
CCD_VEC3_STATIC(CCD_REAL(-0.262869), CCD_REAL(-0.809012), CCD_REAL( 0.525738)),
CCD_VEC3_STATIC(CCD_REAL(-0.850648), CCD_REAL( 0.000000), CCD_REAL( 0.525736)),
CCD_VEC3_STATIC(CCD_REAL(-0.262869), CCD_REAL( 0.809012), CCD_REAL( 0.525738)),
CCD_VEC3_STATIC(CCD_REAL( 0.688190), CCD_REAL( 0.499997), CCD_REAL( 0.525736)),
CCD_VEC3_STATIC(CCD_REAL( 0.525730), CCD_REAL( 0.000000), CCD_REAL( 0.850652)),
CCD_VEC3_STATIC(CCD_REAL( 0.162456), CCD_REAL(-0.499995), CCD_REAL( 0.850654)),
CCD_VEC3_STATIC(CCD_REAL(-0.425323), CCD_REAL(-0.309011), CCD_REAL( 0.850654)),
CCD_VEC3_STATIC(CCD_REAL(-0.425323), CCD_REAL( 0.309011), CCD_REAL( 0.850654)),
CCD_VEC3_STATIC(CCD_REAL( 0.162456), CCD_REAL( 0.499995), CCD_REAL( 0.850654))
};
ccd_vec3_t *ccd_points_on_sphere = points_on_sphere;
size_t ccd_points_on_sphere_len = sizeof(points_on_sphere) / sizeof(ccd_vec3_t);
_ccd_inline ccd_real_t __ccdVec3PointSegmentDist2(const ccd_vec3_t *P,
const ccd_vec3_t *x0,
const ccd_vec3_t *b,
ccd_vec3_t *witness)
{
// The computation comes from solving equation of segment:
// S(t) = x0 + t.d
// where - x0 is initial point of segment
// - d is direction of segment from x0 (|d| > 0)
// - t belongs to <0, 1> interval
//
// Than, distance from a segment to some point P can be expressed:
// D(t) = |x0 + t.d - P|^2
// which is distance from any point on segment. Minimization
// of this function brings distance from P to segment.
// Minimization of D(t) leads to simple quadratic equation that's
// solving is straightforward.
//
// Bonus of this method is witness point for free.
ccd_real_t dist, t;
ccd_vec3_t d, a;
// direction of segment
ccdVec3Sub2(&d, b, x0);
// precompute vector from P to x0
ccdVec3Sub2(&a, x0, P);
t = -CCD_REAL(1.) * ccdVec3Dot(&a, &d);
t /= ccdVec3Len2(&d);
if (t < CCD_ZERO || ccdIsZero(t)){
dist = ccdVec3Dist2(x0, P);
if (witness)
ccdVec3Copy(witness, x0);
}else if (t > CCD_ONE || ccdEq(t, CCD_ONE)){
dist = ccdVec3Dist2(b, P);
if (witness)
ccdVec3Copy(witness, b);
}else{
if (witness){
ccdVec3Copy(witness, &d);
ccdVec3Scale(witness, t);
ccdVec3Add(witness, x0);
dist = ccdVec3Dist2(witness, P);
}else{
// recycling variables
ccdVec3Scale(&d, t);
ccdVec3Add(&d, &a);
dist = ccdVec3Len2(&d);
}
}
return dist;
}
ccd_real_t ccdVec3PointSegmentDist2(const ccd_vec3_t *P,
const ccd_vec3_t *x0, const ccd_vec3_t *b,
ccd_vec3_t *witness)
{
return __ccdVec3PointSegmentDist2(P, x0, b, witness);
}
ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P,
const ccd_vec3_t *x0, const ccd_vec3_t *B,
const ccd_vec3_t *C,
ccd_vec3_t *witness)
{
// Computation comes from analytic expression for triangle (x0, B, C)
// T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
// Then equation for distance is:
// D(s, t) = | T(s, t) - P |^2
// This leads to minimization of quadratic function of two variables.
// The solution from is taken only if s is between 0 and 1, t is
// between 0 and 1 and t + s < 1, otherwise distance from segment is
// computed.
ccd_vec3_t d1, d2, a;
ccd_real_t u, v, w, p, q, r, d;
ccd_real_t s, t, dist, dist2;
ccd_vec3_t witness2;
ccdVec3Sub2(&d1, B, x0);
ccdVec3Sub2(&d2, C, x0);
ccdVec3Sub2(&a, x0, P);
u = ccdVec3Dot(&a, &a);
v = ccdVec3Dot(&d1, &d1);
w = ccdVec3Dot(&d2, &d2);
p = ccdVec3Dot(&a, &d1);
q = ccdVec3Dot(&a, &d2);
r = ccdVec3Dot(&d1, &d2);
d = w * v - r * r;
if (ccdIsZero(d)){
// To avoid division by zero for zero (or near zero) area triangles
s = t = -1.;
}else{
s = (q * r - w * p) / d;
t = (-s * r - q) / w;
}
if ((ccdIsZero(s) || s > CCD_ZERO)
&& (ccdEq(s, CCD_ONE) || s < CCD_ONE)
&& (ccdIsZero(t) || t > CCD_ZERO)
&& (ccdEq(t, CCD_ONE) || t < CCD_ONE)
&& (ccdEq(t + s, CCD_ONE) || t + s < CCD_ONE)){
if (witness){
ccdVec3Scale(&d1, s);
ccdVec3Scale(&d2, t);
ccdVec3Copy(witness, x0);
ccdVec3Add(witness, &d1);
ccdVec3Add(witness, &d2);
dist = ccdVec3Dist2(witness, P);
}else{
dist = s * s * v;
dist += t * t * w;
dist += CCD_REAL(2.) * s * t * r;
dist += CCD_REAL(2.) * s * p;
dist += CCD_REAL(2.) * t * q;
dist += u;
}
}else{
dist = __ccdVec3PointSegmentDist2(P, x0, B, witness);
dist2 = __ccdVec3PointSegmentDist2(P, x0, C, &witness2);
if (dist2 < dist){
dist = dist2;
if (witness)
ccdVec3Copy(witness, &witness2);
}
dist2 = __ccdVec3PointSegmentDist2(P, B, C, &witness2);
if (dist2 < dist){
dist = dist2;
if (witness)
ccdVec3Copy(witness, &witness2);
}
}
return dist;
}

@ -1 +0,0 @@
Subproject commit d961a8122210010e7c2c8f201e61170c13d319b4

@ -1,850 +0,0 @@
//gcc -o aoi aoi.c utils.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "utils.h"
#include "aoi.h"
static int NEARBY_CEIL_OFFSETS[9][2] = {
{0, 0}, // center
{-1, 1}, // TL
{0, 1}, // T
{1, 1}, // TR
{-1, 0}, // L
{1, 0}, // R
{-1, -1}, // BL
{0, -1}, // B
{1, -1}, // BR
};
static double cost_time_in_lua = 0.0;
static double cost_time_in_cal = 0.0;
static double cost_time_in_get_event = 0.0;
static int get_grid_idx(World *w, int x, int y)
{
return (x - 1) * (w->col) + y - 1;
};
static void get_xy_by_grididx(World *w, int grid_idx, int *x, int *y)
{
*x = (grid_idx / w->col) + 1;
*y = grid_idx - ((*x) - 1) * w->col + 1;
return;
}
static int out_of_range(World *w, int grid_idx, int idx)
{
int x1, y1;
get_xy_by_grididx(w, grid_idx, &x1, &y1);
int x2, y2;
get_xy_by_grididx(w, idx, &x2, &y2);
if ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) > 2)
{
return 1;
}
return 0;
}
static HashTable *get_nearby_grids(World *w, Grid *grid)
{
int grid_num = w->row * w->col;
HashTable *ret = hashtbl_create();
int x, y;
get_xy_by_grididx(w, grid->idx, &x, &y);
int i, _x, _y;
for (i = 0; i < 9; i++)
{
_x = x + NEARBY_CEIL_OFFSETS[i][0];
_y = y + NEARBY_CEIL_OFFSETS[i][1];
if (_x >= 1 && _x <= w->row && _y >= 1 && _y <= w->col)
{
int tmp_idx = get_grid_idx(w, _x, _y);
Grid *grid = w->grids[tmp_idx];
hashtbl_upsert(ret, tmp_idx, grid);
//printf("get_nearby_grids %d %d\n",grid->idx,tmp_idx);
}
}
// for (int i = -1; i<=1; i++){
// for (int j= -1; j<=1; j++){
// int index = i*w->col + grid->idx + j;
// if(index >= 0 && index < grid_num){
// Grid* grid = w->grids[index];
// hashtbl_upsert(ret, index, grid);
// }
// }
// }
// local k = i*col + cur_grididx + j
// local grid = grids[k]
// if grid and not ret[k] then
// ret[k] = grid
// end
// end
// end
// return ret
return ret;
}
static void print_event(int grid_idx, char flag, HashTable *events)
{
HashTableIter iter;
hashtbl_iter_reset(&iter);
while (hashtbl_iter(events, &iter))
{
Event *e = (Event *)(iter.node->value);
printf("flag:%c grid_idx:%d event:%c,id:%d,x:%d,y:%d\n", flag, grid_idx, e->e, e->id, e->x, e->y);
}
}
static void get_grid_add_event(Grid *grid, lua_State *L)
{ //你进入某个格子,要知道该格子的事情
int idx_grid_info = lua_gettop(L); //2
lua_rawgeti(L, idx_grid_info, grid->idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_info, grid->idx);
}
int idx_grid_detail = lua_gettop(L); //3
lua_rawgeti(L, idx_grid_detail, 1); //key_idx==1
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_detail, 1);
}
int idx_grid_add_del_update = lua_gettop(L); //4
size_t tbl_len = lua_rawlen(L, idx_grid_add_del_update);
if (tbl_len == 0)
{
int len = 1;
HashTableIter iter;
hashtbl_iter_reset(&iter);
while (hashtbl_iter(grid->caches, &iter))
{
Cache *cache = (Cache *)(iter.node->value);
if (cache->e == 'A' || cache->e == 'U')
{
lua_newtable(L);
lua_pushinteger(L, 1); //'A'
lua_rawseti(L, -2, 1);
lua_pushinteger(L, cache->id);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, cache->x);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, cache->y);
lua_rawseti(L, -2, 4);
lua_rawseti(L, idx_grid_add_del_update, len);
len = len + 1;
}
}
hashtbl_iter_reset(&iter);
while (hashtbl_iter(grid->makers, &iter))
{
Obj *obj = (Obj *)(iter.node->value);
if (!hashtbl_get(grid->caches, obj->id))
{ //如果在cache中且没进入event_adds说明e是D
lua_newtable(L);
lua_pushinteger(L, 1); //'A'
lua_rawseti(L, -2, 1);
lua_pushinteger(L, obj->id);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, obj->x);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, obj->y);
lua_rawseti(L, -2, 4);
lua_rawseti(L, idx_grid_add_del_update, len);
len = len + 1;
}
}
}
}
static void get_grid_del_event(Grid *grid, lua_State *L)
{ //你离开某个格子,要知道该格子的事情
int idx_grid_info = lua_gettop(L); //2
lua_rawgeti(L, idx_grid_info, grid->idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_info, grid->idx);
}
int idx_grid_detail = lua_gettop(L); //3
lua_rawgeti(L, idx_grid_detail, 2); //key_idx==2
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_detail, 2);
}
int idx_grid_add_del_update = lua_gettop(L); //4
size_t tbl_len = lua_rawlen(L, idx_grid_add_del_update);
if (tbl_len == 0)
{
int len = 1;
HashTableIter iter;
hashtbl_iter_reset(&iter);
//cache中还没加进makers的就不管了
while (hashtbl_iter(grid->makers, &iter))
{
Obj *obj = (Obj *)(iter.node->value);
lua_newtable(L);
lua_pushinteger(L, 2); //'D'
lua_rawseti(L, -2, 1);
lua_pushinteger(L, obj->id);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, obj->x);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, obj->y);
lua_rawseti(L, -2, 4);
lua_rawseti(L, idx_grid_add_del_update, len);
len = len + 1;
}
}
}
static void get_grid_update_event(Grid *grid, lua_State *L)
{ //你在某个格子附近晃,要知道该格子的事情
int idx_grid_info = lua_gettop(L); //2
lua_rawgeti(L, idx_grid_info, grid->idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_info, grid->idx);
}
int idx_grid_detail = lua_gettop(L); //3
lua_rawgeti(L, idx_grid_detail, 3); //key_idx==3
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_detail, 3);
}
int idx_grid_add_del_update = lua_gettop(L); //4
size_t tbl_len = lua_rawlen(L, idx_grid_add_del_update);
if (tbl_len == 0)
{
int len = 1;
HashTableIter iter;
hashtbl_iter_reset(&iter);
while (hashtbl_iter(grid->caches, &iter))
{
Cache *cache = (Cache *)(iter.node->value);
lua_newtable(L);
if (cache->e == 'A')
{
lua_pushinteger(L, 1); //'A'
}
else if (cache->e == 'D')
{
lua_pushinteger(L, 2);
}
else
{
lua_pushinteger(L, 3);
}
lua_rawseti(L, -2, 1);
lua_pushinteger(L, cache->id);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, cache->x);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, cache->y);
lua_rawseti(L, -2, 4);
lua_rawseti(L, idx_grid_add_del_update, len);
len = len + 1;
}
}
}
//结果处理
static void add_grid_events_to_watchers(Grid *grid, char e, int id, lua_State *L)
{
//printf("add_grid_events_to_watchers %d %c %d\n", grid->idx, e, id);
//clock_t t1 = clock();
//HashTable* events;
int key_idx;
if (e == 'U')
{ //3
get_grid_update_event(grid, L);
key_idx = 3;
}
else if (e == 'A')
{ //1
get_grid_add_event(grid, L);
key_idx = 1;
}
else if (e == 'D')
{ //2
get_grid_del_event(grid, L);
key_idx = 2;
}
//clock_t t2 = clock();
//double t3 = (double)(t2-t1)/CLOCKS_PER_SEC;
//cost_time_in_get_event += t3;
//clock_t time_begin = clock();
//不copy直接用引用
int idx_ret = 1;
//将events upsert进L
//printf("upsert events succ %d\n",idx_grid_add_del_update);
lua_rawgeti(L, idx_ret, id);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_ret, id);
}
int idx_watcher_ret = lua_gettop(L); //5
size_t tbl_len = lua_rawlen(L, idx_watcher_ret);
lua_pushvalue(L, 4);
lua_rawseti(L, idx_watcher_ret, tbl_len + 1);
lua_pop(L, 3);
// lua_rawgeti(L, idx_watcher_ret, grid->idx);
// if(lua_isnil(L,-1)){
// lua_pop(L,1);
// lua_newtable(L);
// lua_pushvalue(L,-1);
// lua_rawseti(L, idx_watcher_ret, grid->idx);
// }
// int idx_watcher_grid_ret = lua_gettop(L);//6
// lua_pushvalue(L, 4);//引用,idx_grid_add_del_update==4
// lua_rawseti(L, idx_watcher_grid_ret, key_idx);
// lua_pop(L,4);
//clock_t time_end = clock();
//double time_cost = (double)(time_end-time_begin)/CLOCKS_PER_SEC;
//cost_time_in_lua += time_cost;
//printf("===cost_time_in_lua:%f====\n", cost_time_in_lua);
}
//watcher到了grid
static void resolve_change_watcher(World *w, Grid *grid, HashTable *right_grid_map, int pre_idx, int id, lua_State *L)
{
//printf("resolve_change_watcher id:%d grid_idx:%d pre_idx:%d\n",id, grid->idx, pre_idx);
HashTableIter iter;
HashTable *left_grid_map;
if (pre_idx != -1)
{
// int x,y;
// get_xy_by_grididx(w,pre_idx,&x,&y);
// int i, _x, _y;
// for(i=0; i<9; i++) {
// _x = x + NEARBY_CEIL_OFFSETS[i][0];
// _y = y + NEARBY_CEIL_OFFSETS[i][1];
// if (!(_x>=1&&_x<=w->row&&_y>=1&&_y<=w->col)){
// continue;
// }
// int tmp_idx = get_grid_idx(w, _x, _y);
// Grid* tmp_grid = w->grids[tmp_idx];
// if(out_of_range(w, grid->idx, tmp_idx)){
// add_grid_events_to_watchers(tmp_grid, 'D', id, L);
// }
// else{
// add_grid_events_to_watchers(tmp_grid, 'U', id, L);
// }
// }
Grid *old_grid = w->grids[pre_idx];
left_grid_map = get_nearby_grids(w, old_grid);
hashtbl_iter_reset(&iter);
while (hashtbl_iter(left_grid_map, &iter))
{
Grid *tmp_grid = (Grid *)(iter.node->value);
if (hashtbl_get(right_grid_map, tmp_grid->idx))
{
add_grid_events_to_watchers(tmp_grid, 'U', id, L);
}
else
{
add_grid_events_to_watchers(tmp_grid, 'D', id, L);
}
}
}
hashtbl_iter_reset(&iter);
while (hashtbl_iter(right_grid_map, &iter))
{
Grid *tmp_grid = (Grid *)(iter.node->value);
if (pre_idx == -1 || !hashtbl_get(left_grid_map, tmp_grid->idx))
{
add_grid_events_to_watchers(tmp_grid, 'A', id, L);
}
}
if (pre_idx != -1)
{
hashtbl_destroy(left_grid_map);
}
// for (int i = 0; i<9;i++){
// Grid* tmp_grid = grid_list[i];
// if(!tmp_grid){
// continue;
// }
// if(pre_idx!=-1 && !out_of_range(w, pre_idx, tmp_grid->idx)){
// continue;//之前已经get 'U'过了
// }
// add_grid_events_to_watchers(tmp_grid, 'A', id, L);
// }
}
static int grid_add_obj(World *w, Grid *grid, int id, int x, int y, int is_maker, int is_watcher)
{
if (is_maker)
{
if (hashtbl_get(grid->caches, id))
{
//之前可能有D 在里面
Cache *old_cache = (Cache *)hashtbl_get(grid->caches, id);
skynet_free(old_cache);
hashtbl_remove(grid->caches, id);
old_cache = NULL;
//printf("old cache id:%d e:%c x:%d y:%d \n", old_cache->id, old_cache->e, old_cache->x, old_cache->y);
}
Cache *cache = (Cache *)skynet_malloc(sizeof(Cache));
cache->id = id;
cache->x = x;
cache->y = y;
cache->e = 'A';
hashtbl_insert(grid->caches, id, cache);
}
if (is_watcher)
{
Obj *obj = (Obj *)skynet_malloc(sizeof(Obj));
obj->id = id;
obj->x = x;
obj->y = y;
obj->is_maker = is_maker;
obj->is_watcher = is_watcher;
hashtbl_insert(grid->watchers, obj->id, obj);
hashtbl_upsert(w->watcher_grids, grid->idx, NULL);
}
return 0;
}
static int grid_del_obj(World *w, Grid *grid, int id)
{
if (hashtbl_get(grid->makers, id))
{ //已经落地了
//旧的cache清除
if (hashtbl_get(grid->caches, id))
{
Cache *old_cache = (Cache *)hashtbl_get(grid->caches, id);
skynet_free(old_cache);
hashtbl_remove(grid->caches, id);
old_cache = NULL;
}
//添加新的
Obj *obj = (Obj *)hashtbl_get(grid->makers, id);
Cache *cache = (Cache *)skynet_malloc(sizeof(Cache));
cache->id = obj->id;
cache->x = obj->x;
cache->y = obj->y;
cache->e = 'D';
hashtbl_insert(grid->caches, obj->id, cache);
}
else if (hashtbl_get(grid->caches, id))
{ //只是存在cache中
//当你从来没有出现过
//printf("grid_del_obj remove_caches %d\n", id);
Cache *cache = (Cache *)hashtbl_get(grid->caches, id);
skynet_free(cache);
hashtbl_remove(grid->caches, id);
cache = NULL;
}
if (hashtbl_get(grid->watchers, id))
{
//printf("grid_del_obj remove_watchers %d\n", id);
Obj *obj = (Obj *)hashtbl_get(grid->watchers, id);
hashtbl_remove(grid->watchers, id);
if (!obj->is_maker)
{
//如果只是watcher的话释放对象
skynet_free(obj);
obj = NULL;
}
if (grid->watchers->count == 0)
{
hashtbl_remove(w->watcher_grids, grid->idx);
}
}
return 0;
}
static void grid_update_obj(Grid *grid, int id)
{
//watcher不需要update
if (hashtbl_get(grid->makers, id) && !hashtbl_get(grid->caches, id))
{
//之前已经在的且没有caches的才需要添加cache
Obj *obj = (Obj *)hashtbl_get(grid->makers, id);
Cache *cache = (Cache *)skynet_malloc(sizeof(Cache));
cache->id = obj->id;
cache->x = obj->x;
cache->y = obj->y;
cache->e = 'U';
hashtbl_insert(grid->caches, obj->id, cache);
}
}
static void handle_cache(Grid *grid)
{
HashTableIter iter;
hashtbl_iter_reset(&iter);
while (hashtbl_iter(grid->caches, &iter))
{
Cache *cache = (Cache *)(iter.node->value);
iter.node->value = NULL;
if (cache->e == 'A' && !hashtbl_get(grid->makers, cache->id))
{ //之前在makersD了再A就会重复无须处理
//先D了去了其他格子再回来就不需要add_makers了
Obj *obj;
if (hashtbl_get(grid->watchers, cache->id))
{
obj = (Obj *)hashtbl_get(grid->watchers, cache->id);
}
else
{
obj = (Obj *)skynet_malloc(sizeof(Obj));
obj->id = cache->id;
obj->x = cache->x;
obj->y = cache->y;
obj->is_maker = 1;
obj->is_watcher = 0;
}
hashtbl_insert(grid->makers, obj->id, obj);
}
else if (cache->e == 'D')
{
Obj *obj = (Obj *)hashtbl_get(grid->makers, cache->id);
hashtbl_remove(grid->makers, cache->id);
skynet_free(obj);
obj = NULL;
}
skynet_free(cache);
cache = NULL;
}
hashtbl_destroy(grid->caches);
grid->caches = hashtbl_create();
}
static void handle_aoi(World *w, Grid *grid, lua_State *L)
{
HashTable *grid_map = get_nearby_grids(w, grid);
HashTableIter iter2;
HashTableIter iter;
hashtbl_iter_reset(&iter);
//Grid** grid_list = get_nearby_grids(w, grid);
while (hashtbl_iter(grid->watchers, &iter))
{
Obj *watcher = (Obj *)(iter.node->value);
int pre_idx = -1;
int id = watcher->id;
//printf("handle_aoi %d %d\n",grid->idx, id);
if (hashtbl_get(w->pre_where_is, id))
{
int *p_idx = (int *)hashtbl_get(w->pre_where_is, id);
pre_idx = *p_idx;
}
if (pre_idx == grid->idx)
{
hashtbl_iter_reset(&iter2);
while (hashtbl_iter(grid_map, &iter2))
{
Grid *tmp_grid = (Grid *)(iter2.node->value);
// if(id==6) {
// printf("tmp_grid %d\n",tmp_grid->idx);
// }
add_grid_events_to_watchers(tmp_grid, 'U', id, L);
}
// for (int i = 0; i<9;i++){
// Grid* tmp_grid = grid_list[i];
// if(!tmp_grid){
// continue;
// }
// add_grid_events_to_watchers(tmp_grid, 'U', id, L);
// }
}
else
{
resolve_change_watcher(w, grid, grid_map, pre_idx, id, L);
if (hashtbl_get(w->pre_where_is, id))
{
int *p_idx = (int *)hashtbl_get(w->pre_where_is, id);
*p_idx = grid->idx;
}
else
{
int *p_idx = (int *)skynet_malloc(sizeof(int));
*p_idx = grid->idx;
hashtbl_insert(w->pre_where_is, id, p_idx);
}
}
}
hashtbl_destroy(grid_map);
}
World *aoi_create_world(int row, int col)
{
//printf("aoi_create_world %d %d\n",row, col);
World *w = (World *)skynet_malloc(sizeof(World));
w->row = row;
w->col = col;
int grid_num = w->row * w->col;
w->grids = (Grid **)skynet_malloc(grid_num * sizeof(Grid *));
for (int i = 0; i < grid_num; i++)
{
Grid *grid = (Grid *)skynet_malloc(sizeof(Grid));
grid->idx = i;
grid->watchers = hashtbl_create();
grid->makers = hashtbl_create();
grid->caches = hashtbl_create();
w->grids[i] = grid;
}
w->where_is = hashtbl_create();
w->pre_where_is = hashtbl_create();
w->watcher_grids = hashtbl_create();
return w;
}
void aoi_get_cost_time(void *l)
{
lua_State *L = (lua_State *)l;
lua_pushnumber(L, cost_time_in_get_event);
lua_pushnumber(L, cost_time_in_lua);
lua_pushnumber(L, cost_time_in_cal);
cost_time_in_get_event = 0.0;
cost_time_in_lua = 0.0;
cost_time_in_cal = 0.0;
return;
}
void aoi_update_aoi(World *w, void *l)
{
//clock_t time_begin = clock();
lua_State *L = (lua_State *)l;
//printf("=========start update_aoi=========\n");
int grid_num = w->row * w->col;
//抛出事件
//for(int i=0;i<grid_num;i++){
// Grid* grid = w->grids[i];
// handle_aoi(w, grid, L);
//}
HashTableIter iter;
hashtbl_iter_reset(&iter);
while (hashtbl_iter(w->watcher_grids, &iter))
{
int grid_idx = (iter.node->key);
//printf("handle_aoi grid_idx %d\n", grid_idx);
Grid *grid = w->grids[grid_idx];
handle_aoi(w, grid, L);
}
//clock_t time_end = clock();
//处理cache
//printf("handle_cache\n");
for (int i = 0; i < grid_num; i++)
{
Grid *grid = w->grids[i];
handle_cache(grid);
}
//清空每个格子的events 通过lua_state自己清
//printf("clean all grids events\n");
//printf("=========end update_aoi=========\n");
//clock_t time_end = clock();
//double time_cost = (double)(time_end-time_begin)/CLOCKS_PER_SEC;
//cost_time_in_cal += time_cost;
//printf("===time_cost:%f====\n",cost_time_in_cal);
}
int aoi_add_obj(World *w, int id, int x, int y, int is_maker, int is_watcher)
{
int idx = get_grid_idx(w, x, y); //函数结束会释放idx的不能hashtbl_insert(&idx)
Grid *grid = w->grids[idx];
if (hashtbl_get(w->where_is, id) || hashtbl_get(grid->caches, id) || hashtbl_get(grid->watchers, id) || hashtbl_get(grid->makers, id))
{
printf("add_obj duplicated %d\n", id);
return 1;
}
if (!is_maker && !is_watcher)
{
printf("add_obj no watcher_and_maker %d\n", id);
return 2;
}
int *p_idx = (int *)skynet_malloc(sizeof(int));
*p_idx = idx; //不同于p_idx=&idx
hashtbl_insert(w->where_is, id, p_idx);
grid_add_obj(w, grid, id, x, y, is_maker, is_watcher);
return 0;
}
int aoi_del_obj(World *w, int id)
{
int *p_idx = (int *)hashtbl_get(w->where_is, id);
if (!p_idx)
{
printf("del_obj not_exist %d\n", id);
return 1;
}
Grid *grid = w->grids[*p_idx];
grid_del_obj(w, grid, id);
hashtbl_remove(w->where_is, id);
skynet_free(p_idx);
return 0;
}
int aoi_set_obj(World *w, int id, int x, int y)
{
int *p_idx = (int *)hashtbl_get(w->where_is, id);
if (!p_idx)
{
printf("set_obj not_exist %d\n", id);
return 1;
}
int idx = get_grid_idx(w, x, y);
if (idx == *p_idx)
{
Grid *grid = w->grids[idx];
grid_update_obj(grid, id);
}
else
{
Grid *old_grid = w->grids[*p_idx];
Grid *new_grid = w->grids[idx];
int is_maker = 0;
int is_watcher = 0;
if (hashtbl_get(old_grid->makers, id) || hashtbl_get(old_grid->caches, id))
{
is_maker = 1;
}
if (hashtbl_get(old_grid->watchers, id))
{
is_watcher = 1;
}
grid_del_obj(w, old_grid, id);
grid_add_obj(w, new_grid, id, x, y, is_maker, is_watcher);
*p_idx = idx;
}
return 0;
}
// int main() {
// // World* w = aoi_create_world(3,3);
// // aoi_add_obj(w,7,2,2,1,1);
// // aoi_add_obj(w,1,2,2,1,1);
// // aoi_add_obj(w,6,3,3,1,1);
// // //aoi_update_aoi(w);
// // //aoi_update_aoi(w);
// // aoi_set_obj(w,7,2,3);
// // //aoi_update_aoi(w);
// // aoi_add_obj(w,2,1,1,1,1);
// // aoi_set_obj(w,2,1,2);
// // //aoi_update_aoi(w);
// // //先加再删,等于从来没出现过
// // aoi_add_obj(w,3,2,2,1,1);
// // aoi_del_obj(w,3);
// // //aoi_update_aoi(w);
// // aoi_set_obj(w,2,3,3);
// // aoi_set_obj(w,7,1,1);
// //aoi_update_aoi(w);
// // update_aoi(w);
// // printf("======\n");
// // del_obj(w,7);
// // update_aoi(w);
// // printf("=======\n");
// // int grid_idx = get_grid_idx(w,1,2);
// // int x,y;
// // get_xy_by_grididx(w,grid_idx,&x,&y);
// // printf("x:%d y:%d\n", x, y);
// // add_obj(w,2,5,5,1,1);
// // show_world(w);
// // set_obj(w,1,6,6);
// // show_world(w);
// // del_obj(w,1);
// // show_world(w);
// // World* w = aoi_create_world(3,3);
// // for(int i=1;i<=10000;i++)
// // {
// // aoi_add_obj(w,i,1,1,1,1);
// // }
// // HashTable* aoi_results = hashtbl_create();
// // aoi_update_aoi(w, aoi_results);
// // //打印aoi_results
// // HashTableIter iter;
// // hashtbl_iter_reset(&iter);
// // int i = 0;
// // while(hashtbl_iter(aoi_results, &iter)){
// // Result* re=(Result*)(iter.node->value);
// // printf("watcher:%ld\n", iter.node->key);
// // int watcher_id = (int)iter.node->key;
// // HashTableIter tmp_iter;
// // hashtbl_iter_reset(&tmp_iter);
// // while(hashtbl_iter(re->add_results, &tmp_iter)){
// // Event* e=(Event*)(tmp_iter.node->value);
// // //printf("event:%c,id:%d,x:%d,y:%d\n",e->e,e->id,e->x,e->y);
// // i=i+1;
// // printf("i is %d\n",i);
// // }
// // // hashtbl_iter_reset(&tmp_iter);
// // // while(hashtbl_iter(re->del_results, &tmp_iter)){
// // // Event* e=(Event*)(tmp_iter.node->value);
// // // //printf("event:%c,id:%d,x:%d,y:%d\n",e->e,e->id,e->x,e->y);
// // // }
// // // hashtbl_iter_reset(&tmp_iter);
// // // while(hashtbl_iter(re->update_results, &tmp_iter)){
// // // Event* e=(Event*)(tmp_iter.node->value);
// // // //printf("event:%c,id:%d,x:%d,y:%d\n",e->e,e->id,e->x,e->y);
// // // }
// // hashtbl_destroy(re->add_results);
// // hashtbl_destroy(re->del_results);
// // hashtbl_destroy(re->update_results);
// // }
// // printf("clean aoi_results\n");
// // //todo清空aoi_results
// // hashtbl_destroy(aoi_results);
// return 0;
// }

@ -1,58 +0,0 @@
#ifndef _AOI_H
#define _AOI_H
#include "utils.h"
typedef struct aoi_event
{
char e; //"A","U","D"
int id;
int x;
int y;
} Event;
typedef struct aoi_cache
{
char e;
int id;
int x;
int y;
} Cache;
typedef struct aoi_obj
{
int id;
int x;
int y;
int is_maker;
int is_watcher;
} Obj;
typedef struct aoi_grid
{
int idx;
HashTable *watchers;
HashTable *makers;
HashTable *caches;
} Grid;
typedef struct aoi_world
{
int row;
int col;
Grid **grids;
HashTable *where_is; //id在哪个格子 实时的
HashTable *pre_where_is;
HashTable *watcher_grids;
} World;
World *aoi_create_world(int row, int col);
int aoi_add_obj(World *w, int id, int x, int y, int is_maker, int is_watcher);
int aoi_del_obj(World *w, int id);
int aoi_set_obj(World *w, int id, int x, int y);
void aoi_update_aoi(World *w, void *lua_state);
void aoi_get_cost_time(void *lua_state);
#endif

@ -1,39 +0,0 @@
## AOI
对于AOI(area if interest)介绍的文章实在是太多了比如常用的灯塔9grid十字链表等等这些本质上是在面对海量的数据量做裁枝。最近同事聊起来说在做AOI优化部分的工作于是就感兴趣跟他聊起来现在的实现以及优化的方向。 其实现在的实现就是最最标准和简单的9 grid的实现。 每次对象在`add`, `move`, `delete`时,会返回一个集合,表示需要通知的其他对象。 当如果N个对象全部都是在同一个grid里面而且同时产生事件那这个简单的算法会是O(NxN)的性能开销。
-----
我觉得对于aoi来说所做的事情就只有一件事情根据此时的snapshot和上一次的snapshot对比生成diff变化的对象返回给对应的watcher(观察者)。在这段时间内假如A对象从 b点移动到了c点但又回到了c点diff里面将不会包含这个A对象移动的信息。 驱动`AOI`工作应该是每次调用`update`,并不是在操作函数`add`, `move`, `delete`。 这样,可以自己决定在合适的时机(比如在每帧末尾或者固定时间执行)调用`update`获得这段时间需要通知的事件集合这样在面对之前N个对象在同一个grid同时移动的时间开销将会降到O(N)。
但是对每个watcher创建snapshot开销太大在同一个grid里面的watcher中的snapshot是一样的所以可以只需要对grid做snapshot不过这样被修改的grid对象会存储翻倍而且每次`update`时要生成snapshot性能上肯定会无法接受。
其实对于snapshot本身只是为了diff那其实可以在grid上记录下两次`update`之间的改动,在`update`时直接根据改动来生成diff列表之后再把改动合并到grid存储objects的集合中就好这样就避免对整个grid的snapshot。
所以我就实现了 [AOI](https://github.com/lvzixun/aoi)来证明了想法。 ;D
### AOI 内部实现
首先你可以通过`aoi.aoi_new(map_row, map_col, grid_row, grid_col)`来构建一个`aoi_obj``aoi_obj:aoi_add(obj_id, marked, pos_x, pos_y)`接口来向aoi 场景中添加一个对象id为`obj_id`的object所有的object可以是watchermaker或者同时为两者。 只有watcher才会收到maker产生的事件watcher之间不会产生任何事件。 `aoi_obj:aoi_remove(obj_id)
`函数为移除一个对象, `aoi_obj:aoi_set(obj_id, pos_x, pos_y)`更新一个对象,以及`aoi_obj:aoi_update()`更新整个aoi对象返回需要通知的watchers的makers事件。 事件分为三类`D`删除,`A`添加,`U`更新。 每个对象的更新会根据`grid_row`和`grid_col`被存储在对应的grid对象上。 `grid_obj`的定义如下:
~~~.lua
local obj = {
aoi_obj = aoi_obj,
grid_idx = grid_idx,
watchers = false,
objs = {},
touchs = false,
merge = false,
result = {},
}
~~~
其中`watchers`记录了当前grid上面的所有watcher对象id`objs`记录的是上一次`update`之后当前grid的object`touchs`记录的从上一次`update`到现在grid上面有改动的对象信息其中merge和result是在update时会用到的字段。 `aoi_add`, `aoi_set`, `aoi_remove`这些接口最后都会设置到对应的grid的`touchs`中。当执行`update`时会计算出需要通知的有watcher的grids 对每个grid的周围的9个grid下生成对应的diff每个grid的diff会最多包含以下三种:`GD` grid中object被删除事件集`GA`grid中object被添加事件集`GU`grid中object更新事件集。这些结果会存储到`result` table中。 之后根据每个watcher来选择对应的结果集避免反复的计算。
在`update`实现时这里有个优化是从被touch的grid来找到那些watcher还是从有watcher的grid来找到那些grid被touch。 当被touch的grid大于有watch 的grid个数会选择直接从有watcher的grid去处理。反之从touch的grid来处理。这样的好处是避免了update在watcher和 touch的maker差距很大时无效的遍历。
------
最终我在自己机器`Intel(R) Core(TM) i7-4578U CPU @ 3.00GHz`上面测试了在同一个grid添加10K个对象仅仅只需要0.028496s.
### 订阅通知
其实对于服务器来说aoi的工作并不只是只能完全放到服务器来做。根据灯塔算法将整个world划分成等大的grid客户端自己计算统计那些grid需要订阅关心那些grid应该取消订阅。服务器对于每个grid定时同步订阅的watcher数据。
服务器的工作就会变得很简单维护一系列grid上面订阅的对象同时把grid上产生的事件通知给对应的订阅者即可。 客户端当进入新的grid会产生订阅协议服务器将整个grid的状态同步过去。取消订阅时客户端将在对应的grid的对象自己移除同时服务器也不会通知相应grid的事件。驱动全部都是通过客户端来发起 这样服务器所做的工作就只是同步订阅的grid数据这一个简单的事情也很容易通过多个服务做横向扩展。 对于slg来说我觉得这是个比较好的aoi方案。

@ -1,286 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "utils.h"
#include "aoi.h"
// 非实时抛出事件lua层定时aoi_update获得aoi事件
// https://github.com/ssnobin/c_lua_aoi
// https://github.com/lvzixun/aoi
// https://github.com/lvzixun/rainbowCoder/blob/master/post/aoi.md
#define GET_INTEGER(L, index, isnum) \
(int)lua_tointegerx(L, index, &isnum); \
if (!isnum) \
{ \
return luaL_argerror(L, 1, "not number"); \
}
static int create_world(lua_State *L)
{
int isnum;
int row = GET_INTEGER(L, 1, isnum);
int col = GET_INTEGER(L, 2, isnum);
World *w = aoi_create_world(row, col);
if (w == NULL)
{
return luaL_error(L, "create world fail");
}
lua_pushlightuserdata(L, w);
return 1;
}
static int add_obj(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
int isnum;
int id = GET_INTEGER(L, 2, isnum);
int x = GET_INTEGER(L, 3, isnum);
int y = GET_INTEGER(L, 4, isnum);
int is_maker = GET_INTEGER(L, 5, isnum);
int is_watcher = GET_INTEGER(L, 6, isnum);
if (aoi_add_obj(w, id, x, y, is_maker, is_watcher))
{
return luaL_error(L, "add obj fail");
}
return 1;
}
static int del_obj(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
int isnum;
int id = GET_INTEGER(L, 2, isnum);
if (aoi_del_obj(w, id))
{
return luaL_error(L, "del obj fail");
}
return 1;
}
static int set_obj(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
int isnum;
int id = GET_INTEGER(L, 2, isnum);
int x = GET_INTEGER(L, 3, isnum);
int y = GET_INTEGER(L, 4, isnum);
if (aoi_set_obj(w, id, x, y))
{
return luaL_error(L, "set obj fail");
}
return 1;
}
static int update_aoi(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
lua_pop(L, 1);
lua_newtable(L);
lua_newtable(L);
aoi_update_aoi(w, L);
lua_pop(L, 1);
return 1;
}
static int get_time_cost(lua_State *L)
{
aoi_get_cost_time(L);
return 3;
}
static void add_results_to_L(lua_State *L, int grid_idx, int id, int key_idx)
{
int idx_ret = 1;
//将events upsert进L
int idx_grid_info = lua_gettop(L); //2
lua_rawgeti(L, idx_grid_info, grid_idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_info, grid_idx);
}
int idx_grid_detail = lua_gettop(L); //3
lua_rawgeti(L, idx_grid_detail, key_idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_grid_detail, key_idx);
}
int idx_grid_add_del_update = lua_gettop(L); //4
size_t tbl_len = lua_rawlen(L, idx_grid_add_del_update);
if (tbl_len == 0)
{
//printf("just do once 10000 events\n");
for (int j = 1; j <= 10000; j++)
{
lua_newtable(L);
lua_pushinteger(L, 1);
lua_rawseti(L, -2, 1);
lua_pushinteger(L, 100);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, 1);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, 1);
lua_rawseti(L, -2, 4);
lua_rawseti(L, idx_grid_add_del_update, j);
}
}
lua_rawgeti(L, idx_ret, id);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_ret, id);
}
int idx_watcher_ret = lua_gettop(L); //5
lua_rawgeti(L, idx_watcher_ret, grid_idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
lua_rawseti(L, idx_watcher_ret, grid_idx);
}
int idx_watcher_grid_ret = lua_gettop(L); //6
lua_rawgeti(L, idx_watcher_grid_ret, key_idx);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_pushvalue(L, idx_grid_add_del_update); //引用
lua_rawseti(L, idx_watcher_grid_ret, key_idx);
}
lua_pop(L, 4);
}
static int test_lua_table(lua_State *L)
{
lua_newtable(L);
lua_newtable(L);
for (int id = 1; id <= 10000; id++)
{
for (int grid_idx = 0; grid_idx <= 9; grid_idx++)
{
for (int key_idx = 1; key_idx <= 3; key_idx++)
{
add_results_to_L(L, grid_idx, id, key_idx);
}
}
}
lua_pop(L, 1);
return 1;
}
static int test_create(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
lua_newtable(L);
lua_setuservalue(L, 1);
printf("test_create\n");
printf("xx %lu\n", sizeof(w->grids[0]));
Grid *grid = w->grids[0];
printf("push grid userdata\n");
lua_pushlightuserdata(L, grid);
printf("new uservalue\n");
lua_newtable(L);
printf("set uservalue\n");
lua_setuservalue(L, -2);
printf("set grid userdata uservalue\n");
return 0;
}
static int test_set(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
int key = (int)lua_tointeger(L, 2);
int value = (int)lua_tointeger(L, 3);
int type = lua_getuservalue(L, 1);
Obj *obj = (Obj *)skynet_malloc(sizeof(Obj));
obj->id = key;
obj->x = value;
obj->y = value;
obj->is_maker = 1;
obj->is_watcher = 1;
//lua_pushinteger(L,value);
lua_pushlightuserdata(L, obj);
lua_rawseti(L, -2, key);
return 0;
}
static int test_get(lua_State *L)
{
World *w = (World *)lua_touserdata(L, 1);
if (w == NULL)
{
return luaL_argerror(L, 1, "no world");
}
//int key = (int)lua_tointeger(L, 2);
//int type = lua_getuservalue(L,1);
//lua_rawgeti(L,-1,key);
//Obj* obj = (Obj*)lua_touserdata(L,-1);
//printf("obj key is %d\n", obj->id);
//printf("obj value is %d\n", obj->x);
Grid *grid = w->grids[0];
printf("gg1\n");
lua_pushlightuserdata(L, grid);
printf("gg2\n");
int type = lua_getuservalue(L, -1);
printf("grid uservalue is%d\n", type);
return 1;
}
int luaopen_laoi(lua_State *L)
{
luaL_Reg l[] = {
{"create_world", create_world},
{"add_obj", add_obj},
{"del_obj", del_obj},
{"set_obj", set_obj},
{"update_aoi", update_aoi},
{"get_time_cost", get_time_cost},
{"test_lua_table", test_lua_table},
{"test_create", test_create},
{"test_set", test_set},
{"test_get", test_get},
{NULL, NULL},
};
luaL_newlib(L, l);
return 1;
}

@ -1,69 +0,0 @@
local function print_aoi_events(aoi_events)
print("==========print_aoi_events========")
-- for watcher, grid_info in pairs(aoi_events) do
-- print("watcher", watcher)
-- for grid_idx, event_list in pairs(grid_info) do
-- --print("grid_idx", grid_idx)
-- for i = 1, 3 do
-- local sub_event_list = event_list[i]
-- if sub_event_list then
-- for _, e in ipairs(sub_event_list) do
-- if(e[1]==1 or e[1] == 'A') then
-- print(string.format("event:A,id:%d,x:%d,y:%d",e[2],e[3],e[4]))
-- elseif(e[1]==2 or e[1] == 'D') then
-- print(string.format("event:D,id:%d,x:%d,y:%d",e[2],e[3],e[4]))
-- else
-- print(string.format("event:U,id:%d,x:%d,y:%d",e[2],e[3],e[4]))
-- end
-- end
-- end
-- end
-- end
-- end
for watcher, watch_ret in pairs(aoi_events) do
print("watcher", watcher)
for _, data in ipairs(watch_ret) do
for _, e in ipairs(data) do
if (e[1] == 1 or e[1] == 'A') then
print(string.format("event:A,id:%d,x:%d,y:%d", e[2], e[3], e[4]))
elseif (e[1] == 2 or e[1] == 'D') then
print(string.format("event:D,id:%d,x:%d,y:%d", e[2], e[3], e[4]))
else
print(string.format("event:U,id:%d,x:%d,y:%d", e[2], e[3], e[4]))
end
end
end
end
end
local function my_aoi_test()
local my_aoi = require "laoi"
local world = my_aoi.create_world(4, 3)
my_aoi.add_obj(world, 7, 2, 2, 1, 1) -- my_aoi.add_obj(world, 7, 2,2,1,1)
my_aoi.add_obj(world, 1, 2, 2, 1, 1)
my_aoi.add_obj(world, 6, 3, 3, 1, 1)
print_aoi_events(my_aoi.update_aoi(world))
print_aoi_events(my_aoi.update_aoi(world))
my_aoi.set_obj(world, 7, 2, 3)
print_aoi_events(my_aoi.update_aoi(world))
my_aoi.add_obj(world, 2, 1, 1, 1, 1)
my_aoi.set_obj(world, 2, 1, 2)
print_aoi_events(my_aoi.update_aoi(world))
my_aoi.add_obj(world, 3, 2, 2, 1, 1)
my_aoi.del_obj(world, 3)
print_aoi_events(my_aoi.update_aoi(world))
my_aoi.set_obj(world, 2, 3, 3)
my_aoi.set_obj(world, 7, 1, 1)
print_aoi_events(my_aoi.update_aoi(world))
my_aoi.set_obj(world, 2, 3, 2)
my_aoi.set_obj(world, 2, 3, 1)
print_aoi_events(my_aoi.update_aoi(world))
end
my_aoi_test()

@ -1,252 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#include "utils.h"
#define HASH_TABLE_MIN_HASH_SIZE 16
#define HASH_TABLE_MAX_HASH_SIZE 10240
#define HASH_TABLE_MIN_LOAD_FACTOR 0.1
#define HASH_TABLE_MAX_LOAD_FACTOR 0.8
#define HASH_TABLE_HASH_FUNC(tbl, key) ((key) % (tbl)->hash_sz)
HashTable *hashtbl_create()
{
HashTable *tbl = (HashTable *)skynet_malloc(sizeof(HashTable));
tbl->hash_sz = HASH_TABLE_MIN_HASH_SIZE;
tbl->count = 0;
tbl->min_resize_cnt = (int)(tbl->hash_sz * HASH_TABLE_MIN_LOAD_FACTOR);
tbl->max_resize_cnt = (int)(tbl->hash_sz * HASH_TABLE_MAX_LOAD_FACTOR);
HashTableNode **nodes = (HashTableNode **)skynet_malloc(sizeof(HashTableNode *) * tbl->hash_sz);
int n;
for (n = 0; n < tbl->hash_sz; n++)
{
nodes[n] = NULL;
}
tbl->nodes = nodes;
return tbl;
}
void hashtbl_destroy(HashTable *tbl)
{
int n;
HashTableNode *p, *next_p;
for (n = 0; n < tbl->hash_sz; n++)
{
p = tbl->nodes[n];
tbl->nodes[n] = NULL;
while (p != NULL)
{
next_p = p->next;
skynet_free(p);
p = next_p;
}
}
skynet_free(tbl->nodes);
skynet_free(tbl);
return;
}
static int _hashtbl_resize(HashTable *tbl, int new_hash_sz)
{
HashTableNode **new_nodes = (HashTableNode **)skynet_malloc(sizeof(HashTableNode *) * new_hash_sz);
int old_hash_sz = tbl->hash_sz;
HashTableNode **old_nodes = tbl->nodes;
tbl->nodes = new_nodes;
tbl->hash_sz = new_hash_sz;
tbl->min_resize_cnt = (int)(tbl->hash_sz * HASH_TABLE_MIN_LOAD_FACTOR);
tbl->max_resize_cnt = (int)(tbl->hash_sz * HASH_TABLE_MAX_LOAD_FACTOR);
int n, hash_key;
HashTableNode *p, *next_p;
for (n = 0; n < new_hash_sz; n++)
{
new_nodes[n] = NULL;
}
for (n = 0; n < old_hash_sz; n++)
{
p = old_nodes[n];
old_nodes[n] = NULL;
while (p != NULL)
{
next_p = p->next;
hash_key = p->key % new_hash_sz;
p->next = new_nodes[hash_key];
new_nodes[hash_key] = p;
p = next_p;
}
}
skynet_free(old_nodes);
return 0;
}
static int _hashtbl_insert(HashTable *tbl, int hash_key, uint64_t key, void *value)
{
HashTableNode *node = skynet_malloc(sizeof(HashTableNode));
node->key = key;
node->value = value;
node->next = tbl->nodes[hash_key];
tbl->nodes[hash_key] = node;
tbl->count++;
if (tbl->hash_sz < HASH_TABLE_MAX_HASH_SIZE && tbl->count > tbl->max_resize_cnt)
{
_hashtbl_resize(tbl, tbl->hash_sz * 2);
}
return 0;
}
int hashtbl_insert(HashTable *tbl, uint64_t key, void *value)
{
int hash_key = HASH_TABLE_HASH_FUNC(tbl, key);
HashTableNode *p = tbl->nodes[hash_key];
while (p != NULL)
{
if (p->key == key)
{
printf("table_insert fail, key<%llu>, already exist\n", key);
assert(0);
return 1;
}
p = p->next;
}
return _hashtbl_insert(tbl, hash_key, key, value);
}
int hashtbl_upsert(HashTable *tbl, uint64_t key, void *value)
{
int hash_key = HASH_TABLE_HASH_FUNC(tbl, key);
HashTableNode *p = tbl->nodes[hash_key];
while (p != NULL)
{
if (p->key == key)
{
p->value = value;
return 0;
}
p = p->next;
}
return _hashtbl_insert(tbl, hash_key, key, value);
}
int hashtbl_has(HashTable *tbl, uint64_t key)
{
HashTableNode *p = tbl->nodes[HASH_TABLE_HASH_FUNC(tbl, key)];
while (p != NULL)
{
if (p->key == key)
{
return 1;
}
p = p->next;
}
return 0;
}
void *hashtbl_get(HashTable *tbl, uint64_t key)
{
HashTableNode *p = tbl->nodes[HASH_TABLE_HASH_FUNC(tbl, key)];
while (p != NULL)
{
if (p->key == key)
{
return p->value;
}
p = p->next;
}
return 0;
}
int hashtbl_remove(HashTable *tbl, uint64_t key)
{
int hash_key = HASH_TABLE_HASH_FUNC(tbl, key);
HashTableNode *free_p;
HashTableNode **p = &(tbl->nodes[hash_key]);
int hash_sz = tbl->hash_sz;
while ((*p) != NULL)
{
if ((*p)->key != key)
{
p = &((*p)->next);
continue;
}
free_p = *p;
*p = free_p->next;
skynet_free(free_p);
free_p = NULL;
tbl->count--;
if ((hash_sz > HASH_TABLE_MIN_LOAD_FACTOR) && (tbl->count < tbl->min_resize_cnt))
{
int min_hash_sz = (int)(tbl->count / HASH_TABLE_MAX_LOAD_FACTOR) + 1;
if (min_hash_sz < HASH_TABLE_MIN_HASH_SIZE)
{
min_hash_sz = HASH_TABLE_MIN_HASH_SIZE;
}
int max_hash_sz = 2 * min_hash_sz;
while (hash_sz >= min_hash_sz)
{
if (hash_sz < max_hash_sz)
{
break;
}
hash_sz = hash_sz / 2;
}
_hashtbl_resize(tbl, hash_sz);
}
return 1;
}
return 0;
}
void hashtbl_iter_reset(HashTableIter *iter)
{
iter->hash_sz = -1;
iter->count = 0;
iter->node = NULL;
return;
}
int hashtbl_iter(HashTable *tbl, HashTableIter *iter)
{
if (tbl->count <= iter->count)
{
return 0;
}
if (iter->node)
{
iter->node = iter->node->next;
}
while (!iter->node)
{
iter->hash_sz++;
if (iter->hash_sz >= tbl->hash_sz)
{
break;
}
iter->node = tbl->nodes[iter->hash_sz];
}
if (!iter->node)
{
return 0;
}
iter->count++;
return 1;
}
void hashtbl_foreach(HashTable *tbl, HashTableIterFunc func, void *ud)
{
HashTableIter iter;
hashtbl_iter_reset(&iter);
while (hashtbl_iter(tbl, &iter))
{
func(ud, iter.node->key, iter.node->value);
}
}

@ -1,53 +0,0 @@
#ifndef _UTILS_H
#define _UTILS_H
#include <stdint.h>
#include "skynet_malloc.h"
typedef struct hashtbl_node
{
uint64_t key;
void *value;
struct hashtbl_node *next;
} HashTableNode;
typedef struct hashtbl
{
int hash_sz;
int count;
int max_resize_cnt;
int min_resize_cnt;
HashTableNode **nodes;
} HashTable;
typedef struct hashtbl_iter
{
int hash_sz;
int count;
HashTableNode *node;
} HashTableIter;
typedef void (*HashTableIterFunc)(void *ud, uint64_t key, void *value);
HashTable *hashtbl_create();
void hashtbl_destroy(HashTable *tbl);
int hashtbl_has(HashTable *tbl, uint64_t key);
void *hashtbl_get(HashTable *tbl, uint64_t key);
int hashtbl_insert(HashTable *tbl, uint64_t key, void *value);
int hashtbl_upsert(HashTable *tbl, uint64_t key, void *value);
int hashtbl_remove(HashTable *tbl, uint64_t key);
int hashtbl_resize(HashTable *tbl, int new_hash_size);
void hashtbl_iter_reset(HashTableIter *iter);
int hashtbl_iter(HashTable *tbl, HashTableIter *iter);
void hashtbl_foreach(HashTable *tbl, HashTableIterFunc func, void *ud);
#endif

@ -1,121 +0,0 @@
ifdef MINGW_PREFIX
MINGW=1
else
LINUX=1
endif
# Lua version
LUAVER?=5.3
# Base install directory
ifdef LINUX
PREFIX?=/usr/local
endif
ifdef MINGW
PREFIX?=$(MINGW_PREFIX)
endif
# Directory where to install Lua modules
L_DIR=$(PREFIX)/share/lua/$(LUAVER)
# Directory where to install Lua C modules
C_DIR=$(PREFIX)/lib/lua/$(LUAVER)
# Directory where to install C headers
H_DIR=$(PREFIX)/include
# Directory where to install C libraries
S_DIR=$(PREFIX)/lib
ifeq ($(D),1)
DEBUG=1
endif
ifdef LINUX
LIBS = -lccd -lpthread
endif
ifdef MINGW
LIBS = -llua
endif
Tgt := moonccd
Src := $(wildcard *.c)
Objs := $(Src:.c=.o)
INCDIR = -I. -I/usr/include/lua$(LUAVER)
COPT += -O2
#COPT += -O0 -g
#COPT += -m32
COPT += -Wfatal-errors
COPT += -Wall -Wextra -Wpedantic
COPT += -DCOMPAT53_PREFIX=moonccd_compat_
COPT += -std=gnu99
COPT += -DLUAVER=$(LUAVER)
ifdef LINUX
COPT += -fpic
COPT += -DLINUX
endif
ifdef MINGW
COPT += -DMINGW
endif
ifdef DEBUG
COPT += -DDEBUG
COPT += -Wshadow -Wsign-compare -Wundef -Wwrite-strings
COPT += -Wdisabled-optimization -Wdeclaration-after-statement
COPT += -Wmissing-prototypes -Wstrict-prototypes -Wnested-externs
COPT += -Wold-style-definition
#COPT += -Wc++-compat
endif
override CFLAGS = $(COPT) $(INCDIR)
default: build
where:
@echo "PREFIX="$(PREFIX)
@echo "LUAVER="$(LUAVER)
@echo $(L_DIR)
@echo $(C_DIR)
@echo $(H_DIR)
@echo $(S_DIR)
clean:
@-rm -f *.so *.dll *.o *.err *.map *.S *~ *.log
@-rm -f $(Tgt).symbols
install:
@-mkdir -pv $(H_DIR)
@-mkdir -pv $(C_DIR)
@-mkdir -pv $(S_DIR)
@-mkdir -pv $(L_DIR)
@-cp -fpv $(Tgt).h $(H_DIR)
@-cp -fpvr ../$(Tgt) $(L_DIR)
ifdef LINUX
@-cp -fpv $(Tgt).so $(C_DIR)
@-ln -fsv $(C_DIR)/$(Tgt).so $(S_DIR)/lib$(Tgt).so
endif
ifdef MINGW
@-cp -fpv $(Tgt).dll $(C_DIR)
endif
uninstall:
@-rm -f $(H_DIR)/$(Tgt).h
@-rm -f $(C_DIR)/$(Tgt).so
@-rm -f $(S_DIR)/lib$(Tgt).so
@-rm -fr $(L_DIR)/$(Tgt)
@-rm -f $(C_DIR)/$(Tgt).dll
build: clean $(Tgt)
symbols: build
@objdump -T $(Tgt).so > $(Tgt).symbols
$(Tgt): $(Objs)
ifdef LINUX
@$(CXX) -shared -o $(Tgt).so $(Objs) $(LIBDIR) $(LIBS)
endif
ifdef MINGW
@-$(CXX) -shared -o $(Tgt).dll $(Objs) $(LIBDIR) $(LIBS)
endif
@-rm -f $(Objs)
@echo

@ -1,317 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
static ud_t *Ud = NULL;
#define PAR 1
#define OBJ1 2
#define OBJ2 3
static void FirstDir(const void *obj1, const void *obj2, vec3_t *dir);
static void Support(const void *obj_, const vec3_t *dir, vec3_t *vec);
static void Center(const void *obj_, vec3_t *center);
static int freeccd(lua_State *L, ud_t *ud)
{
ccd_t *ccd = (ccd_t *)ud->handle;
if (!freeuserdata(L, ud, "ccdpar"))
return 0;
Free(L, ccd);
return 0;
}
static int newccd(lua_State *L, ccd_t *ccd, int ref[6])
{
ud_t *ud;
ud = newuserdata(L, ccd, CCDPAR_MT, "ccdpar");
ud->parent_ud = NULL;
ud->destructor = freeccd;
memcpy(ud->ref, ref, 6 * sizeof(int));
return 1;
}
static int New(lua_State *L)
{
ccd_t ccd, *ccdp;
int ref[6];
int t = lua_type(L, 1);
CCD_INIT(&ccd);
memset(ref, 0, 6 * sizeof(int));
switch (t)
{
case LUA_TNONE:
case LUA_TNIL:
return argerror(L, 1, ERR_NOTPRESENT);
case LUA_TTABLE:
break;
default:
return argerror(L, 1, ERR_TABLE);
}
#define checkfn(name, ccdfield, Func, ref) \
do \
{ \
lua_getfield(L, 1, name); \
if (lua_isfunction(L, -1)) \
/* this also unfererences any previous ref: */ \
{ \
Reference(L, -1, ref); \
ccd.ccdfield = Func; \
} \
else if (!lua_isnoneornil(L, -1)) \
return argerror(L, 1, ERR_FUNCTION); \
lua_pop(L, 1); \
} while (0)
checkfn("first_dir", first_dir, FirstDir, ref[0]);
checkfn("support1", support1, Support, ref[1]);
checkfn("support2", support2, Support, ref[2]);
checkfn("center1", center1, Center, ref[3]);
checkfn("center2", center2, Center, ref[4]);
#undef checkfn
lua_getfield(L, 1, "max_iterations");
ccd.max_iterations = luaL_optinteger(L, -1, ccd.max_iterations);
lua_pop(L, 1);
lua_getfield(L, 1, "epa_tolerance");
ccd.epa_tolerance = luaL_optnumber(L, -1, ccd.epa_tolerance);
lua_pop(L, 1);
lua_getfield(L, 1, "mpr_tolerance");
ccd.mpr_tolerance = luaL_optnumber(L, -1, ccd.mpr_tolerance);
lua_pop(L, 1);
lua_getfield(L, 1, "dist_tolerance");
ccd.dist_tolerance = luaL_optnumber(L, -1, ccd.dist_tolerance);
lua_pop(L, 1);
ccdp = Malloc(L, sizeof(ccd_t));
memcpy(ccdp, &ccd, sizeof(ccd_t));
return newccd(L, ccdp, ref);
}
static void FirstDir(const void *obj1, const void *obj2, vec3_t *dir)
{
#define L moonccd_L
int rc;
int t = lua_gettop(L);
(void)obj1;
(void)obj2;
lua_rawgeti(L, LUA_REGISTRYINDEX, Ud->ref[0]);
lua_pushvalue(L, OBJ1);
lua_pushvalue(L, OBJ2);
rc = lua_pcall(L, 2, 1, 0);
if (rc != LUA_OK)
lua_error(L);
checkvec3(L, -1, dir);
lua_settop(L, t);
#undef L
}
static void Support(const void *obj_, const vec3_t *dir, vec3_t *vec)
{
#define L moonccd_L
int ref, rc;
int obj = (ptrdiff_t)obj_;
int t = lua_gettop(L);
switch (obj)
{
case OBJ1:
ref = Ud->ref[1];
break;
case OBJ2:
ref = Ud->ref[2];
break;
default:
unexpected(L);
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
lua_pushvalue(L, obj);
pushvec3(L, dir);
rc = lua_pcall(L, 2, 1, 0);
if (rc != LUA_OK)
lua_error(L);
checkvec3(L, -1, vec);
lua_settop(L, t);
#undef L
}
static void Center(const void *obj_, vec3_t *center)
{
#define L moonccd_L
int ref, rc;
int obj = (ptrdiff_t)obj_;
int t = lua_gettop(L);
switch (obj)
{
case OBJ1:
ref = Ud->ref[3];
break;
case OBJ2:
ref = Ud->ref[4];
break;
default:
unexpected(L);
return;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
lua_pushvalue(L, obj);
rc = lua_pcall(L, 1, 1, 0);
if (rc != LUA_OK)
lua_error(L);
checkvec3(L, -1, center);
lua_settop(L, t);
#undef L
}
static int GJKIntersect(lua_State *L)
{
ccd_t *ccd = checkccd(L, PAR, &Ud);
luaL_checkany(L, OBJ1);
luaL_checkany(L, OBJ2);
lua_pushboolean(L, ccdGJKIntersect((void *)OBJ1, (void *)OBJ2, ccd));
return 1;
}
static int GJKSeparate(lua_State *L)
{
int rc;
vec3_t sep;
ccd_t *ccd = checkccd(L, PAR, &Ud);
luaL_checkany(L, OBJ1);
luaL_checkany(L, OBJ2);
rc = ccdGJKSeparate((void *)OBJ1, (void *)OBJ2, ccd, &sep);
switch (rc)
{
case 0:
lua_pushboolean(L, 1);
pushvec3(L, &sep);
return 2;
case -1:
lua_pushboolean(L, 0);
return 1;
case -2:
return errmemory(L);
default:
break;
}
return unexpected(L);
}
static int GJKPenetration(lua_State *L)
{
int rc;
double depth;
vec3_t dir, pos;
ccd_t *ccd = checkccd(L, PAR, &Ud);
luaL_checkany(L, OBJ1);
luaL_checkany(L, OBJ2);
rc = ccdGJKPenetration((void *)OBJ1, (void *)OBJ2, ccd, &depth, &dir, &pos);
switch (rc)
{
case 0:
lua_pushboolean(L, 1);
lua_pushnumber(L, depth);
pushvec3(L, &dir);
pushvec3(L, &pos);
return 4;
case -1:
lua_pushboolean(L, 0);
return 1;
case -2:
return errmemory(L);
default:
break;
}
return unexpected(L);
}
static int MPRIntersect(lua_State *L)
{
ccd_t *ccd = checkccd(L, PAR, &Ud);
luaL_checkany(L, OBJ1);
luaL_checkany(L, OBJ2);
lua_pushboolean(L, ccdMPRIntersect((void *)OBJ1, (void *)OBJ2, ccd));
return 1;
}
static int MPRPenetration(lua_State *L)
{
int rc;
double depth;
vec3_t dir, pos;
ccd_t *ccd = checkccd(L, PAR, &Ud);
luaL_checkany(L, OBJ1);
luaL_checkany(L, OBJ2);
rc = ccdMPRPenetration((void *)OBJ1, (void *)OBJ2, ccd, &depth, &dir, &pos);
switch (rc)
{
case 0:
lua_pushboolean(L, 1);
lua_pushnumber(L, depth);
pushvec3(L, &dir);
pushvec3(L, &pos);
return 4;
case -1:
lua_pushboolean(L, 0);
return 1;
case -2:
return errmemory(L);
default:
break;
}
return unexpected(L);
}
DESTROY_FUNC(ccd)
static const struct luaL_Reg Methods[] =
{
{"free", Destroy},
{"gjk_intersect", GJKIntersect},
{"gjk_separate", GJKSeparate},
{"gjk_penetration", GJKPenetration},
{"mpr_intersect", MPRIntersect},
{NULL, NULL} /* sentinel */
};
static const struct luaL_Reg MetaMethods[] =
{
{"__gc", Destroy},
{NULL, NULL} /* sentinel */
};
static const struct luaL_Reg Functions[] =
{
{"new", New},
{"free", Destroy},
{"gjk_intersect", GJKIntersect},
{"gjk_separate", GJKSeparate},
{"gjk_penetration", GJKPenetration},
{"mpr_intersect", MPRIntersect},
{"mpr_penetration", MPRPenetration},
{NULL, NULL} /* sentinel */
};
void moonccd_open_ccd(lua_State *L)
{
udata_define(L, CCDPAR_MT, Methods, MetaMethods);
luaL_setfuncs(L, Functions, 0);
}

@ -1,324 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
#define GLMATH_COMPAT (tovec3 != LUA_NOREF)
/* References to the MoonGLMATH functions used to convert pushed values to glmath objects. */
static int tovec3 = LUA_NOREF;
static int toquat = LUA_NOREF;
int isglmathcompat(void)
{
return GLMATH_COMPAT;
}
int glmathcompat(lua_State *L, int on)
{
if (on)
{
if (GLMATH_COMPAT)
return 0; /* already enabled */
if (luaL_dostring(L, "return require('moonglmath').tovec3") != 0)
lua_error(L);
tovec3 = luaL_ref(L, LUA_REGISTRYINDEX);
if (luaL_dostring(L, "return require('moonglmath').toquat") != 0)
lua_error(L);
toquat = luaL_ref(L, LUA_REGISTRYINDEX);
}
else
{
if (!GLMATH_COMPAT)
return 0; /* already disabled */
luaL_unref(L, LUA_REGISTRYINDEX, tovec3);
tovec3 = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, toquat);
toquat = LUA_NOREF;
}
return 0;
}
/* vec3_t ----------------------------------------------------------*/
int testvec3(lua_State *L, int arg, vec3_t *dst)
{
int isnum;
int t = lua_type(L, arg);
switch (t)
{
case LUA_TNONE:
case LUA_TNIL:
return ERR_NOTPRESENT;
case LUA_TTABLE:
break;
default:
return ERR_TABLE;
}
#define POP \
if (!isnum) \
{ \
lua_pop(L, 1); \
return ERR_VALUE; \
} \
lua_pop(L, 1);
lua_rawgeti(L, arg, 1);
dst->v[0] = lua_tonumberx(L, -1, &isnum);
POP
lua_rawgeti(L, arg, 2);
dst->v[1] = lua_tonumberx(L, -1, &isnum);
POP
lua_rawgeti(L, arg, 3);
dst->v[2] = lua_tonumberx(L, -1, &isnum);
POP
#undef POP
return 0;
}
int optvec3(lua_State *L, int arg, vec3_t *dst)
{
int ec = testvec3(L, arg, dst);
if (ec < 0)
return argerror(L, arg, ec);
return ec;
}
int checkvec3(lua_State *L, int arg, vec3_t *dst)
{
int ec = testvec3(L, arg, dst);
if (ec)
return argerror(L, arg, ec);
return ec;
}
void pushvec3(lua_State *L, const vec3_t *val)
{
if (GLMATH_COMPAT)
lua_rawgeti(L, LUA_REGISTRYINDEX, tovec3);
lua_newtable(L);
lua_pushnumber(L, val->v[0]);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, val->v[1]);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, val->v[2]);
lua_rawseti(L, -2, 3);
if (GLMATH_COMPAT && lua_pcall(L, 1, 1, 0) != LUA_OK)
{
unexpected(L);
return;
}
}
vec3_t *checkvec3list(lua_State *L, int arg, int *countp, int *err)
/* Check if the value at arg is a table of vecs and returns the corresponding
* array of vec3_t, stroing the size in *countp. The array is Malloc()'d and the
* caller is in charge of Free()ing it.
* If err=NULL, raises an error on failure, otherwise returns NULL and stores
* the ERR_XXX code in *err.
*/
{
int count, i;
vec3_t *dst = NULL;
*countp = 0;
#define ERR(ec) \
do \
{ \
if (err) \
*err = (ec); \
else \
argerror(L, arg, (ec)); \
return NULL; \
} while (0)
if (lua_isnoneornil(L, arg))
ERR(ERR_NOTPRESENT);
if (lua_type(L, arg) != LUA_TTABLE)
ERR(ERR_TABLE);
count = luaL_len(L, arg);
if (count == 0)
ERR(ERR_EMPTY);
dst = MallocNoErr(L, count * sizeof(vec3_t));
if (!dst)
ERR(ERR_MEMORY);
for (i = 0; i < count; i++)
{
lua_rawgeti(L, arg, i + 1);
if (testvec3(L, -1, &dst[i]) != 0)
{
Free(L, dst);
ERR(ERR_TYPE);
}
lua_pop(L, 1);
}
#undef ERR
*countp = count;
if (err)
*err = 0;
return dst;
}
void pushvec3list(lua_State *L, const vec3_t *vecs, int count)
{
int i;
lua_newtable(L);
for (i = 0; i < count; i++)
{
pushvec3(L, &vecs[i]);
lua_rawseti(L, -2, i + 1);
}
}
/* quat_t ----------------------------------------------------------*/
int testquat(lua_State *L, int arg, quat_t *dst)
{
int isnum;
int t = lua_type(L, arg);
switch (t)
{
case LUA_TNONE:
case LUA_TNIL:
return ERR_NOTPRESENT;
case LUA_TTABLE:
break;
default:
return ERR_TABLE;
}
#define POP \
if (!isnum) \
{ \
lua_pop(L, 1); \
return ERR_VALUE; \
} \
lua_pop(L, 1);
lua_rawgeti(L, arg, 1);
dst->q[3] = lua_tonumberx(L, -1, &isnum);
POP // w
lua_rawgeti(L, arg, 2);
dst->q[0] = lua_tonumberx(L, -1, &isnum);
POP // x
lua_rawgeti(L, arg, 3);
dst->q[1] = lua_tonumberx(L, -1, &isnum);
POP // y
lua_rawgeti(L, arg, 4);
dst->q[2] = lua_tonumberx(L, -1, &isnum);
POP // z
#undef POP
return 0;
}
int optquat(lua_State *L, int arg, quat_t *dst)
{
int ec = testquat(L, arg, dst);
if (ec < 0)
return argerror(L, arg, ec);
return ec;
}
int checkquat(lua_State *L, int arg, quat_t *dst)
{
int ec = testquat(L, arg, dst);
if (ec)
return argerror(L, arg, ec);
return ec;
}
void pushquat(lua_State *L, const quat_t *val)
{
if (GLMATH_COMPAT)
lua_rawgeti(L, LUA_REGISTRYINDEX, toquat);
lua_newtable(L);
lua_pushnumber(L, val->q[3]);
lua_rawseti(L, -2, 1); // w
lua_pushnumber(L, val->q[0]);
lua_rawseti(L, -2, 2); // x
lua_pushnumber(L, val->q[1]);
lua_rawseti(L, -2, 3); // y
lua_pushnumber(L, val->q[2]);
lua_rawseti(L, -2, 4); // z
if (GLMATH_COMPAT && lua_pcall(L, 1, 1, 0) != LUA_OK)
{
unexpected(L);
return;
}
}
quat_t *checkquatlist(lua_State *L, int arg, int *countp, int *err)
/* Check if the value at arg is a table of vecs and returns the corresponding
* array of quat_t, stroing the size in *countp. The array is Malloc()'d and the
* caller is in charge of Free()ing it.
* If err=NULL, raises an error on failure, otherwise returns NULL and stores
* the ERR_XXX code in *err.
*/
{
int count, i;
quat_t *dst = NULL;
*countp = 0;
#define ERR(ec) \
do \
{ \
if (err) \
*err = (ec); \
else \
argerror(L, arg, (ec)); \
return NULL; \
} while (0)
if (lua_isnoneornil(L, arg))
ERR(ERR_NOTPRESENT);
if (lua_type(L, arg) != LUA_TTABLE)
ERR(ERR_TABLE);
count = luaL_len(L, arg);
if (count == 0)
ERR(ERR_EMPTY);
dst = MallocNoErr(L, count * sizeof(quat_t));
if (!dst)
ERR(ERR_MEMORY);
for (i = 0; i < count; i++)
{
lua_rawgeti(L, arg, i + 1);
if (testquat(L, -1, &dst[i]) != 0)
{
Free(L, dst);
ERR(ERR_TYPE);
}
lua_pop(L, 1);
}
#undef ERR
*countp = count;
if (err)
*err = 0;
return dst;
}
void pushquatlist(lua_State *L, const quat_t *vecs, int count)
{
int i;
lua_newtable(L);
for (i = 0; i < count; i++)
{
pushquat(L, &vecs[i]);
lua_rawseti(L, -2, i + 1);
}
}

@ -1,238 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef internalDEFINED
#define internalDEFINED
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "moonccd.h"
#define TOSTR_(x) #x
#define TOSTR(x) TOSTR_(x)
#include "tree.h"
#include "objects.h"
/* Note: all the dynamic symbols of this library (should) start with 'moonccd_' .
* The only exception is the luaopen_moonccd() function, which is searched for
* with that name by Lua.
* MoonCCD's string references on the Lua registry also start with 'moonccd_'.
*/
#if 0
/* .c */
#define moonccd_
#endif
/* flags.c */
#define checkflags(L, arg) luaL_checkinteger((L), (arg))
#define optflags(L, arg, defval) luaL_optinteger((L), (arg), (defval))
#define pushflags(L, val) lua_pushinteger((L), (val))
/* utils.c */
void moonccd_utils_init(lua_State *L);
#define copytable moonccd_copytable
int copytable(lua_State *L);
#define noprintf moonccd_noprintf
int noprintf(const char *fmt, ...);
#define now moonccd_now
double now(void);
#define sleeep moonccd_sleeep
void sleeep(double seconds);
#define since(t) (now() - (t))
#define notavailable moonccd_notavailable
int notavailable(lua_State *L, ...);
#define Malloc moonccd_Malloc
void *Malloc(lua_State *L, size_t size);
#define MallocNoErr moonccd_MallocNoErr
void *MallocNoErr(lua_State *L, size_t size);
#define Strdup moonccd_Strdup
char *Strdup(lua_State *L, const char *s);
#define Free moonccd_Free
void Free(lua_State *L, void *ptr);
#define checkboolean moonccd_checkboolean
int checkboolean(lua_State *L, int arg);
#define testboolean moonccd_testboolean
int testboolean(lua_State *L, int arg, int *err);
#define optboolean moonccd_optboolean
int optboolean(lua_State *L, int arg, int d);
#define checklightuserdata moonccd_checklightuserdata
void *checklightuserdata(lua_State *L, int arg);
#define checklightuserdataorzero moonccd_checklightuserdataorzero
void *checklightuserdataorzero(lua_State *L, int arg);
#define optlightuserdata moonccd_optlightuserdata
void *optlightuserdata(lua_State *L, int arg);
#define testindex moonccd_testindex
int testindex(lua_State *L, int arg, int *err);
#define checkindex moonccd_checkindex
int checkindex(lua_State *L, int arg);
#define optindex moonccd_optindex
int optindex(lua_State *L, int arg, int optval);
#define pushindex moonccd_pushindex
void pushindex(lua_State *L, int val);
/* datastructs.c */
#define isglmathcompat moonccd_isglmathcompat
int isglmathcompat(void);
#define glmathcompat moonccd_glmathcompat
int glmathcompat(lua_State *L, int on);
#define testvec3 moonccd_testvec3
int testvec3(lua_State *L, int arg, vec3_t *dst);
#define optvec3 moonccd_optvec3
int optvec3(lua_State *L, int arg, vec3_t *dst);
#define checkvec3 moonccd_checkvec3
int checkvec3(lua_State *L, int arg, vec3_t *dst);
#define pushvec3 moonccd_pushvec3
void pushvec3(lua_State *L, const vec3_t *val);
#define checkvec3list moonccd_checkvec3list
vec3_t *checkvec3list(lua_State *L, int arg, int *countp, int *err);
#define pushvec3list moonccd_pushvec3list
void pushvec3list(lua_State *L, const vec3_t *vecs, int count);
#define testquat moonccd_testquat
int testquat(lua_State *L, int arg, quat_t *dst);
#define optquat moonccd_optquat
int optquat(lua_State *L, int arg, quat_t *dst);
#define checkquat moonccd_checkquat
int checkquat(lua_State *L, int arg, quat_t *dst);
#define pushquat moonccd_pushquat
void pushquat(lua_State *L, const quat_t *val);
#define checkquatlist moonccd_checkquatlist
quat_t *checkquatlist(lua_State *L, int arg, int *countp, int *err);
#define pushquatlist moonccd_pushquatlist
void pushquatlist(lua_State *L, const quat_t *vecs, int count);
/* Internal error codes */
#define ERR_NOTPRESENT 1
#define ERR_SUCCESS 0
#define ERR_GENERIC -1
#define ERR_TYPE -2
#define ERR_ELEMTYPE -3
#define ERR_VALUE -4
#define ERR_ELEMVALUE -5
#define ERR_TABLE -6
#define ERR_FUNCTION -7
#define ERR_EMPTY -8
#define ERR_MEMORY -9
#define ERR_MALLOC_ZERO -10
#define ERR_LENGTH -11
#define ERR_POOL -12
#define ERR_BOUNDARIES -13
#define ERR_RANGE -14
#define ERR_FOPEN -15
#define ERR_OPERATION -16
#define ERR_UNKNOWN -17
#define errstring moonccd_errstring
const char *errstring(int err);
/* tracing.c */
#define trace_objects moonccd_trace_objects
extern int trace_objects;
/* main.c */
extern lua_State *moonccd_L;
int luaopen_moonccd(lua_State *L);
void moonccd_open_tracing(lua_State *L);
void moonccd_open_misc(lua_State *L);
void moonccd_open_ccd(lua_State *L);
/*------------------------------------------------------------------------------*
| Debug and other utilities |
*------------------------------------------------------------------------------*/
/* If this is printed, it denotes a suspect bug: */
#define UNEXPECTED_ERROR "unexpected error (%s, %d)", __FILE__, __LINE__
#define unexpected(L) luaL_error((L), UNEXPECTED_ERROR)
/* Errors with internal error code (ERR_XXX) */
#define failure(L, errcode) luaL_error((L), errstring((errcode)))
#define argerror(L, arg, errcode) luaL_argerror((L), (arg), errstring((errcode)))
#define errmemory(L) luaL_error((L), errstring((ERR_MEMORY)))
#define notsupported(L) luaL_error((L), "operation not supported")
#define badvalue(L, s) lua_pushfstring((L), "invalid value '%s'", (s))
/* Reference/unreference variables on the Lua registry */
#define Unreference(L, ref) \
do \
{ \
if ((ref) != LUA_NOREF) \
{ \
luaL_unref((L), LUA_REGISTRYINDEX, (ref)); \
(ref) = LUA_NOREF; \
} \
} while (0)
#define Reference(L, arg, ref) \
do \
{ \
Unreference((L), (ref)); \
lua_pushvalue(L, (arg)); \
(ref) = luaL_ref(L, LUA_REGISTRYINDEX); \
} while (0)
/* DEBUG -------------------------------------------------------- */
#if defined(DEBUG)
#define DBG printf
#define TR() \
do \
{ \
printf("trace %s %d\n", __FILE__, __LINE__); \
} while (0)
#define BK() \
do \
{ \
printf("break %s %d\n", __FILE__, __LINE__); \
getchar(); \
} while (0)
#define TSTART double ts = now();
#define TSTOP \
do \
{ \
ts = since(ts); \
ts = ts * 1e6; \
printf("%s %d %.3f us\n", __FILE__, __LINE__, ts); \
ts = now(); \
} while (0);
#else
#define DBG noprintf
#define TR()
#define BK()
#define TSTART \
do \
{ \
} while (0)
#define TSTOP \
do \
{ \
} while (0)
#endif /* DEBUG ------------------------------------------------- */
#endif /* internalDEFINED */

@ -1,106 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
// https://github.com/stetre/moonccd
lua_State *moonccd_L;
static void AtExit(void)
{
if (moonccd_L)
{
moonccd_L = NULL;
}
}
static int AddVersions(lua_State *L)
{
lua_pushstring(L, "_VERSION");
lua_pushstring(L, "MoonCCD " MOONCCD_VERSION);
lua_settable(L, -3);
lua_pushstring(L, "_LIBCCD_VERSION");
lua_pushfstring(L, "libccd %s", VERSION);
lua_settable(L, -3);
return 0;
}
static int AddConstants(lua_State *L)
{
lua_pushnumber(L, CCD_EPS);
lua_setfield(L, -2, "EPS");
lua_pushnumber(L, CCD_REAL_MAX);
lua_setfield(L, -2, "REAL_MAX");
return 0;
}
static int IsGlmathCompat(lua_State *L)
{
lua_pushboolean(L, isglmathcompat());
return 1;
}
static int GlmathCompat(lua_State *L)
{
int on = checkboolean(L, 1);
glmathcompat(L, on);
return 0;
}
static const struct luaL_Reg Functions[] =
{
{"is_glmath_compat", IsGlmathCompat},
{"glmath_compat", GlmathCompat},
{NULL, NULL} /* sentinel */
};
int luaopen_moonccd(lua_State *L)
/* Lua calls this function to load the module */
{
moonccd_L = L;
moonccd_utils_init(L);
atexit(AtExit);
lua_newtable(L); /* the module table */
AddVersions(L);
AddConstants(L);
luaL_setfuncs(L, Functions, 0);
moonccd_open_tracing(L);
moonccd_open_misc(L);
moonccd_open_ccd(L);
// #if 0 //@@
// /* Add functions implemented in Lua */
// lua_pushvalue(L, -1); lua_setglobal(L, "moonccd");
// if(luaL_dostring(L, "require('moonccd.datastructs')") != 0) lua_error(L);
// lua_pushnil(L); lua_setglobal(L, "moonccd");
// #endif
return 1;
}

@ -1,311 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
static int Origin(lua_State *L)
{
pushvec3(L, ccd_vec3_origin);
return 1;
}
static int Points_on_sphere(lua_State *L)
{
pushvec3list(L, ccd_points_on_sphere, ccd_points_on_sphere_len);
return 1;
}
static int Sign(lua_State *L)
{
double val = luaL_checknumber(L, 1);
lua_pushinteger(L, ccdSign(val));
return 1;
}
static int IsZero(lua_State *L)
{
double val = luaL_checknumber(L, 1);
lua_pushboolean(L, ccdIsZero(val));
return 1;
}
static int Eq(lua_State *L)
{
double a = luaL_checknumber(L, 1);
double b = luaL_checknumber(L, 2);
lua_pushboolean(L, ccdEq(a, b));
return 1;
}
static int Vec3Eq(lua_State *L)
{
vec3_t a, b;
checkvec3(L, 1, &a);
checkvec3(L, 2, &b);
lua_pushboolean(L, ccdVec3Eq(&a, &b));
return 1;
}
static int Vec3Len2(lua_State *L)
{
vec3_t v;
checkvec3(L, 1, &v);
lua_pushnumber(L, ccdVec3Len2(&v));
return 1;
}
static int Vec3Dist2(lua_State *L)
{
vec3_t a, b;
checkvec3(L, 1, &a);
checkvec3(L, 2, &b);
lua_pushnumber(L, ccdVec3Dist2(&a, &b));
return 1;
}
static int Vec3Copy(lua_State *L)
{
vec3_t v;
checkvec3(L, 1, &v);
// ccdVec3Copy(&v, &w);
pushvec3(L, &v);
return 1;
}
static int Vec3Sub(lua_State *L)
{
vec3_t a, b;
checkvec3(L, 1, &a);
checkvec3(L, 2, &b);
ccdVec3Sub(&a, &b);
pushvec3(L, &a);
return 1; // a - b
}
static int Vec3Add(lua_State *L)
{
vec3_t a, b;
checkvec3(L, 1, &a);
checkvec3(L, 2, &b);
ccdVec3Add(&a, &b);
pushvec3(L, &a);
return 1; // a + b
}
static int Vec3Scale(lua_State *L)
{
vec3_t v;
double k = luaL_checknumber(L, 2);
checkvec3(L, 1, &v);
ccdVec3Scale(&v, k); /* d = d * k; */
pushvec3(L, &v);
return 1; // d*v
}
static int Vec3Normalize(lua_State *L)
{
vec3_t v;
checkvec3(L, 1, &v);
ccdVec3Normalize(&v);
pushvec3(L, &v);
return 1; // v/|v|
}
static int Vec3Dot(lua_State *L)
{
vec3_t a, b;
checkvec3(L, 1, &a);
checkvec3(L, 2, &b);
lua_pushnumber(L, ccdVec3Dot(&a, &b));
return 1; // a·b
}
static int Vec3Cross(lua_State *L)
{
vec3_t a, b, c;
checkvec3(L, 1, &a);
checkvec3(L, 2, &b);
ccdVec3Cross(&c, &a, &b);
pushvec3(L, &c);
return 1; // a x b
}
static int Vec3PointSegmentDist2(lua_State *L)
{
vec3_t P, a, b, witness;
checkvec3(L, 1, &P);
checkvec3(L, 2, &a);
checkvec3(L, 3, &b);
lua_pushnumber(L, ccdVec3PointSegmentDist2(&P, &a, &b, &witness));
pushvec3(L, &witness);
return 2;
}
static int Vec3PointTriDist2(lua_State *L)
{
vec3_t P, a, b, c, witness;
checkvec3(L, 1, &P);
checkvec3(L, 2, &a);
checkvec3(L, 3, &b);
checkvec3(L, 4, &c);
lua_pushnumber(L, ccdVec3PointTriDist2(&P, &a, &b, &c, &witness));
pushvec3(L, &witness);
return 2;
}
static int QuatLen2(lua_State *L)
{
quat_t q;
checkquat(L, 1, &q);
lua_pushnumber(L, ccdQuatLen2(&q));
return 1;
}
static int QuatLen(lua_State *L)
{
quat_t q;
checkquat(L, 1, &q);
lua_pushnumber(L, ccdQuatLen(&q));
return 1;
}
static int QuatCopy(lua_State *L)
{
quat_t q;
checkquat(L, 1, &q);
// ccdQuatCopy(&dst, q);
pushquat(L, &q);
return 1;
}
static int QuatNormalize(lua_State *L)
{
int rc;
quat_t q;
checkquat(L, 1, &q);
rc = ccdQuatNormalize(&q);
if (rc != 0)
return argerror(L, 1, ERR_LENGTH);
pushquat(L, &q);
return 1;
}
static int QuatSetAngleAxis(lua_State *L)
{
quat_t q;
vec3_t axis;
double angle = luaL_checknumber(L, 1);
checkvec3(L, 2, &axis);
ccdQuatSetAngleAxis(&q, angle, &axis);
pushquat(L, &q);
return 1;
}
static int QuatScale(lua_State *L)
{
quat_t q;
double k = luaL_checknumber(L, 2);
checkquat(L, 1, &q);
ccdQuatScale(&q, k);
pushquat(L, &q);
return 1;
}
static int QuatMul(lua_State *L)
{
quat_t q, q1;
checkquat(L, 1, &q);
checkquat(L, 2, &q1);
ccdQuatMul(&q, &q1);
pushquat(L, &q);
return 1;
}
static int QuatInvert(lua_State *L)
{
int rc;
quat_t q;
checkquat(L, 1, &q);
rc = ccdQuatInvert(&q);
if (rc != 0)
return argerror(L, 1, ERR_LENGTH);
pushquat(L, &q);
return 1;
}
static int QuatRotVec(lua_State *L)
{
vec3_t v;
quat_t q;
checkvec3(L, 1, &v);
checkquat(L, 2, &q);
ccdQuatRotVec(&v, &q);
pushvec3(L, &v);
return 1;
}
static const struct luaL_Reg Functions[] =
{
{"origin", Origin},
{"points_on_sphere", Points_on_sphere},
{"sign", Sign},
{"is_zero", IsZero},
{"eq", Eq},
// { "vx", Vec3X }, --> x, y, z = v[1], v[2], v[3]
// { "vy", Vec3Y },
// { "vz", Vec3Z },
{"veq", Vec3Eq},
{"vlen2", Vec3Len2},
{"vdist2", Vec3Dist2},
// { "vset", Vec3Set }, --> v = { x, y, z }
{"vcopy", Vec3Copy},
{"vsub", Vec3Sub},
{"vadd", Vec3Add},
// { "vsub2", Vec3Sub2 },
{"vscale", Vec3Scale},
{"vnormalize", Vec3Normalize},
{"vdot", Vec3Dot},
{"vcross", Vec3Cross},
{"point_segment_dist2", Vec3PointSegmentDist2},
{"point_triangle_dist2", Vec3PointTriDist2},
{"qlen2", QuatLen2},
{"qlen", QuatLen},
// { "qset", QuatSet }, --> q = { w, x, y, z }
{"qcopy", QuatCopy},
{"qnormalize", QuatNormalize},
{"qset_angle_axis", QuatSetAngleAxis},
{"qscale", QuatScale},
{"qmul", QuatMul},
// { "qmul2", QuatMul2 },
{"qinvert", QuatInvert},
// { "qinvert2", QuatInvert2 },
{"vrotate", QuatRotVec},
{NULL, NULL} /* sentinel */
};
void moonccd_open_misc(lua_State *L)
{
luaL_setfuncs(L, Functions, 0);
}

@ -1,47 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef moonccdDEFINED
#define moonccdDEFINED
#include <lua.h>
#include "lualib.h"
#include "lauxlib.h"
#include <ccd/config.h>
#include <ccd/ccd.h>
#include <ccd/vec3.h>
#include <ccd/quat.h>
#ifndef CCD_DOUBLE
#error("MoonCCD requires CCD_DOUBLE")
#endif
#define MOONCCD_VERSION "0.1"
#ifndef VERSION /* @@ defined in ccd/config.h, but not n the version installed on Ubuntu */
#define VERSION "2.0"
#endif
#endif /* moonccdDEFINED */

@ -1,216 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
ud_t *newuserdata(lua_State *L, void *handle, const char *mt, const char *tracename)
{
ud_t *ud;
/* we use handle as search key */
ud = (ud_t *)udata_new(L, sizeof(ud_t), (uint64_t)(uintptr_t)handle, mt);
memset(ud, 0, sizeof(ud_t));
ud->handle = handle;
MarkValid(ud);
if (trace_objects)
printf("create %s %p (%p)\n", tracename, (void *)ud, handle);
return ud;
}
int freeuserdata(lua_State *L, ud_t *ud, const char *tracename)
{
/* The 'Valid' mark prevents double calls when an object is explicitly destroyed,
* and subsequently deleted also by the GC (the ud sticks around until the GC
* collects it, so we mark it as invalid when the object is explicitly destroyed
* by the script, or implicitly destroyed because child of a destroyed object). */
int i;
if (!IsValid(ud))
return 0;
CancelValid(ud);
if (ud->info)
Free(L, ud->info);
for (i = 0; i < 6; i++)
if (ud->ref[i] != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, ud->ref[i]);
if (trace_objects)
printf("delete %s %p (%p)\n", tracename, (void *)ud, ud->handle);
udata_free(L, (uint64_t)(uintptr_t)ud->handle);
return 1;
}
static int freeifchild(lua_State *L, const void *mem, const char *mt, const void *parent_ud)
/* callback for udata_scan */
{
ud_t *ud = (ud_t *)mem;
(void)mt;
if (IsValid(ud) && (ud->parent_ud == parent_ud))
ud->destructor(L, ud);
return 0;
}
int freechildren(lua_State *L, const char *mt, ud_t *parent_ud)
/* calls the self destructor for all 'mt' objects that are children of the given parent_ud */
{
return udata_scan(L, mt, parent_ud, freeifchild);
}
int pushuserdata(lua_State *L, ud_t *ud)
{
if (!IsValid(ud))
return unexpected(L);
return udata_push(L, (uint64_t)(uintptr_t)ud->handle);
}
ud_t *userdata(const void *handle)
{
ud_t *ud = (ud_t *)udata_mem((uint64_t)(uintptr_t)handle);
if (ud && IsValid(ud))
return ud;
return NULL;
}
void *testxxx(lua_State *L, int arg, ud_t **udp, const char *mt)
{
ud_t *ud = (ud_t *)udata_test(L, arg, mt);
if (ud && IsValid(ud))
{
if (udp)
*udp = ud;
return ud->handle;
}
if (udp)
*udp = NULL;
return 0;
}
#if 0
void *testoneofxxx(lua_State *L, int arg, ud_t **udp, char **mtp)
{
void *handle = NULL;
int i = 0;
char *mt = NULL;
while((mt = mtp[i++]) != NULL)
{
handle = testxxx(L, arg, udp, mt);
if(handle) return handle;
}
if(udp) *udp = NULL;
return 0;
}
#endif
void *checkxxx(lua_State *L, int arg, ud_t **udp, const char *mt)
{
ud_t *ud = (ud_t *)udata_test(L, arg, mt);
if (ud && IsValid(ud))
{
if (udp)
*udp = ud;
return ud->handle;
}
lua_pushfstring(L, "not a %s", mt);
luaL_argerror(L, arg, lua_tostring(L, -1));
return 0;
}
void *optxxx(lua_State *L, int arg, ud_t **udp, const char *mt)
/* This differs from testxxx in that it fails in case the argument is
* something different than either none/nil or the expected userdata type
*/
{
if (lua_isnoneornil(L, arg))
{
if (udp)
*udp = NULL;
return 0;
}
return checkxxx(L, arg, udp, mt);
}
int pushxxx(lua_State *L, void *handle)
{
return udata_push(L, (uint64_t)(uintptr_t)handle);
}
void **checkxxxlist(lua_State *L, int arg, int *count, int *err, const char *mt)
/* xxx* checkxxxlist(lua_State *L, int arg, int *count, int *err)
* Checks if the variable at arg on the Lua stack is a list of xxx objects.
* On success, returns an array of xxx handles and sets its length in *count.
* The array s Malloc'd and must be released by the caller using Free(L, ...).
* On error, sets *err to ERR_XXX, *count to 0, and returns NULL.
*/
{
void **list;
int i;
*count = 0;
*err = 0;
if (lua_isnoneornil(L, arg))
{
*err = ERR_NOTPRESENT;
return NULL;
}
if (lua_type(L, arg) != LUA_TTABLE)
{
*err = ERR_TABLE;
return NULL;
}
*count = luaL_len(L, arg);
if (*count == 0)
{
*err = ERR_EMPTY;
return NULL;
}
list = (void **)MallocNoErr(L, sizeof(void *) * (*count));
if (!list)
{
*count = 0;
*err = ERR_MEMORY;
return NULL;
}
for (i = 0; i < *count; i++)
{
lua_rawgeti(L, arg, i + 1);
list[i] = (void *)(uintptr_t)testxxx(L, -1, NULL, mt);
if (!list[i])
{
Free(L, list);
*count = 0;
*err = ERR_TYPE;
return NULL;
}
lua_pop(L, 1);
}
return list;
}
int setmetatable(lua_State *L, const char *mt)
/* Sets the metatable of the table on top of the stack */
{
luaL_getmetatable(L, mt);
lua_setmetatable(L, -2);
return 0;
}

@ -1,157 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef objectsDEFINED
#define objectsDEFINED
#include "tree.h"
#include "udata.h"
/* libccd renaming (for internal use) */
#define vec3_t ccd_vec3_t
#define quat_t ccd_quat_t
#define real_t ccd_real_t
/* Objects' metatable names */
#define CCDPAR_MT "moonccd_ccdpar" /* ccd_t */
/* Userdata memory associated with objects */
#define ud_t moonccd_ud_t
typedef struct moonccd_ud_s ud_t;
struct moonccd_ud_s
{
void *handle; /* the object handle bound to this userdata */
int (*destructor)(lua_State *L, ud_t *ud); /* self destructor */
ud_t *parent_ud; /* the ud of the parent object */
uint32_t marks;
int ref[6]; /* refs for callbacks, automatically unreferenced at destruction */
void *info; /* object specific info (ud_info_t, subject to Free() at destruction, if not NULL) */
};
/* Marks. m_ = marks word (uint32_t) , i_ = bit number (0 .. 31) */
#define MarkGet(m_, i_) (((m_) & ((uint32_t)1 << (i_))) == ((uint32_t)1 << (i_)))
#define MarkSet(m_, i_) \
do \
{ \
(m_) = ((m_) | ((uint32_t)1 << (i_))); \
} while (0)
#define MarkReset(m_, i_) \
do \
{ \
(m_) = ((m_) & (~((uint32_t)1 << (i_)))); \
} while (0)
#define IsValid(ud) MarkGet((ud)->marks, 0)
#define MarkValid(ud) MarkSet((ud)->marks, 0)
#define CancelValid(ud) MarkReset((ud)->marks, 0)
#if 0
/* .c */
#define moonccd_
#endif
#define setmetatable moonccd_setmetatable
int setmetatable(lua_State *L, const char *mt);
#define newuserdata moonccd_newuserdata
ud_t *newuserdata(lua_State *L, void *handle, const char *mt, const char *tracename);
#define freeuserdata moonccd_freeuserdata
int freeuserdata(lua_State *L, ud_t *ud, const char *tracename);
#define pushuserdata moonccd_pushuserdata
int pushuserdata(lua_State *L, ud_t *ud);
#define freechildren moonccd_freechildren
int freechildren(lua_State *L, const char *mt, ud_t *parent_ud);
#define userdata_unref(L, handle) udata_unref((L), (handle))
#define UD(handle) userdata((handle)) /* dispatchable objects only */
#define userdata moonccd_userdata
ud_t *userdata(const void *handle);
#define testxxx moonccd_testxxx
void *testxxx(lua_State *L, int arg, ud_t **udp, const char *mt);
#define checkxxx moonccd_checkxxx
void *checkxxx(lua_State *L, int arg, ud_t **udp, const char *mt);
#define optxxx moonccd_optxxx
void *optxxx(lua_State *L, int arg, ud_t **udp, const char *mt);
#define pushxxx moonccd_pushxxx
int pushxxx(lua_State *L, void *handle);
#define checkxxxlist moonccd_checkxxxlist
void **checkxxxlist(lua_State *L, int arg, int *count, int *err, const char *mt);
#if 0 // 7yy
/* zzz.c */
#define checkzzz(L, arg, udp) (zzz_t *)checkxxx((L), (arg), (udp), ZZZ_MT)
#define testzzz(L, arg, udp) (zzz_t *)testxxx((L), (arg), (udp), ZZZ_MT)
#define optzzz(L, arg, udp) (zzz_t *)optxxx((L), (arg), (udp), ZZZ_MT)
#define pushzzz(L, handle) pushxxx((L), (void *)(handle))
#define checkzzzlist(L, arg, count, err) checkxxxlist((L), (arg), (count), (err), ZZZ_MT)
#endif
/* ccd.c */
#define checkccd(L, arg, udp) (ccd_t *)checkxxx((L), (arg), (udp), CCDPAR_MT)
#define testccd(L, arg, udp) (ccd_t *)testxxx((L), (arg), (udp), CCDPAR_MT)
#define optccd(L, arg, udp) (ccd_t *)optxxx((L), (arg), (udp), CCDPAR_MT)
#define pushccd(L, handle) pushxxx((L), (void *)(handle))
#define checkccdlist(L, arg, count, err) checkxxxlist((L), (arg), (count), (err), CCDPAR_MT)
#define RAW_FUNC(xxx) \
static int Raw(lua_State *L) \
{ \
lua_pushinteger(L, (uintptr_t)check##xxx(L, 1, NULL)); \
return 1; \
}
#define TYPE_FUNC(xxx) /* NONCL */ \
static int Type(lua_State *L) \
{ \
(void)check##xxx(L, 1, NULL); \
lua_pushstring(L, "" #xxx); \
return 1; \
}
#define DESTROY_FUNC(xxx) \
static int Destroy(lua_State *L) \
{ \
ud_t *ud; \
(void)test##xxx(L, 1, &ud); \
if (!ud) \
return 0; /* already deleted */ \
return ud->destructor(L, ud); \
}
#define PARENT_FUNC(xxx) \
static int Parent(lua_State *L) \
{ \
ud_t *ud; \
(void)check##xxx(L, 1, &ud); \
if (!ud->parent_ud) \
return 0; \
return pushuserdata(L, ud->parent_ud); \
}
#endif /* objectsDEFINED */

@ -1,54 +0,0 @@
-- MoonCCD example: hello.lua
local ccd = require("moonccd")
-- Support function for box objects:
local function support(obj, dir)
-- Assume obj is a user defined table containing info about the object,
-- in this case a box: obj = { pos, quat, x, y, z } where pos is the
-- position, quat is the rotation, and x, y, z are the dimensions.
-- Apply the rotation on direction vector:
local qinv = ccd.qinvert(obj.quat)
dir = ccd.vrotate(dir, qinv)
-- Compute the support point in the specified direction:
local v = {0.5 * ccd.sign(dir[1]) * obj.x, 0.5 * ccd.sign(dir[2]) * obj.y, 0.5 * ccd.sign(dir[3]) * obj.z}
-- Transform support point according to the rotation of the object and return it
v = ccd.vrotate(v, obj.quat)
v = ccd.vadd(v, obj.pos)
return v
end
-- Create two box objects:
local box1 = {
pos = {-5, 0, 0},
quat = {1, 0, 0, 0},
x = 1,
y = 2,
z = 1,
}
local box2 = {
pos = {0, 0, 0},
quat = {1, 0, 0, 0},
x = 2,
y = 1,
z = 2,
}
-- Create and initialize the ccd parameters:
local ccdpar = ccd.new({
support1 = support, -- support function for first object
support2 = support, -- support function for second object
max_iterations = 100, -- maximum number of iterations
})
for i = 0, 99 do
local intersect = ccd.gjk_intersect(ccdpar, box1, box2)
-- now intersect is true if the two boxes intersect, false otherwise
-- print(i, intersect, box1.pos[1], box2.pos[1])
if i < 35 or i > 65 then
assert(not intersect)
elseif i ~= 35 and i ~= 65 then
assert(intersect)
end
-- move first box along the x axis:
box1.pos[1] = box1.pos[1] + 0.1
end

@ -1,62 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
int trace_objects = 0;
static int TraceObjects(lua_State *L)
{
trace_objects = checkboolean(L, 1);
return 0;
}
static int Now(lua_State *L)
{
lua_pushnumber(L, now());
return 1;
}
static int Since(lua_State *L)
{
double t = luaL_checknumber(L, 1);
lua_pushnumber(L, since(t));
return 1;
}
/* ----------------------------------------------------------------------- */
static const struct luaL_Reg Functions[] =
{
{"trace_objects", TraceObjects},
{"now", Now},
{"since", Since},
{NULL, NULL} /* sentinel */
};
void moonccd_open_tracing(lua_State *L)
{
luaL_setfuncs(L, Functions, 0);
}

@ -1,858 +0,0 @@
/* $OpenBSD: tree.h,v 1.14 2015/05/25 03:07:49 deraadt Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* 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 THE AUTHOR ``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 THE AUTHOR 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.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name \
{ \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ \
NULL \
}
#define SPLAY_INIT(root) \
do \
{ \
(root)->sph_root = NULL; \
} while (0)
#define SPLAY_ENTRY(type) \
struct \
{ \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) \
do \
{ \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) \
do \
{ \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_LINKLEFT(head, tmp, field) \
do \
{ \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (0)
#define SPLAY_LINKRIGHT(head, tmp, field) \
do \
{ \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) \
do \
{ \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) \
{ \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) \
{ \
elm = SPLAY_LEFT(elm, field); \
} \
} \
else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
{ \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} \
else \
{ \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if (__comp < 0) \
{ \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} \
else if (__comp > 0) \
{ \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} \
else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
{ \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
{ \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} \
else \
{ \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root))) \
{ \
if (__comp < 0) \
{ \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0) \
{ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} \
else if (__comp > 0) \
{ \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0) \
{ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
__left = __right = &__node; \
\
while (1) \
{ \
if (__comp < 0) \
{ \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0) \
{ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} \
else if (__comp > 0) \
{ \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) \
{ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name \
{ \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ \
NULL \
}
#define RB_INIT(root) \
do \
{ \
(root)->rbh_root = NULL; \
} while (0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct \
{ \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) \
do \
{ \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (0)
#define RB_SET_BLACKRED(black, red, field) \
do \
{ \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) \
do \
{ \
} while (0)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) \
do \
{ \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) \
{ \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) \
{ \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} \
else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) \
do \
{ \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) \
{ \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) \
{ \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} \
else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, )
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
attr struct type *name##_RB_FIND(struct name *, struct type *); \
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
attr struct type *name##_RB_NEXT(struct type *); \
attr struct type *name##_RB_PREV(struct type *); \
attr struct type *name##_RB_MINMAX(struct name *, int);
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, )
#define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) && \
RB_COLOR(parent, field) == RB_RED) \
{ \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) \
{ \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field); \
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) \
{ \
RB_ROTATE_LEFT(head, parent, tmp, field); \
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} \
else \
{ \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field); \
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) \
{ \
RB_ROTATE_RIGHT(head, parent, tmp, field); \
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) \
{ \
if (RB_LEFT(parent, field) == elm) \
{ \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field); \
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \
{ \
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} \
else \
{ \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) \
{ \
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field))) \
RB_COLOR(oleft, field) = RB_BLACK; \
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field); \
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
RB_ROTATE_LEFT(head, parent, tmp, field); \
elm = RB_ROOT(head); \
break; \
} \
} \
else \
{ \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) \
{ \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field); \
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) \
{ \
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} \
else \
{ \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) \
{ \
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field))) \
RB_COLOR(oright, field) = RB_BLACK; \
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field); \
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
RB_ROTATE_RIGHT(head, parent, tmp, field); \
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else \
{ \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field))) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) \
{ \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} \
else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) \
{ \
if (RB_LEFT(RB_PARENT(old, field), field) == old) \
RB_LEFT(RB_PARENT(old, field), field) = elm; \
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm; \
RB_AUGMENT(RB_PARENT(old, field)); \
} \
else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) \
{ \
left = parent; \
do \
{ \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field))); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) \
{ \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} \
else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
attr struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) \
{ \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) \
{ \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} \
else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
attr struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) \
{ \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* Finds the first node greater than or equal to the search key */ \
attr struct type * \
name##_RB_NFIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \
int comp; \
while (tmp) \
{ \
comp = cmp(elm, tmp); \
if (comp < 0) \
{ \
res = tmp; \
tmp = RB_LEFT(tmp, field); \
} \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (res); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) \
{ \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} \
else \
{ \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else \
{ \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) \
{ \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} \
else \
{ \
if (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else \
{ \
while (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
attr struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) \
{ \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
(x) = (y))
#endif /* _SYS_TREE_H_ */

@ -1,315 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <string.h>
#include <stdlib.h>
#include "tree.h"
#include "udata.h"
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
struct moonccd_udata_s
{
RB_ENTRY(moonccd_udata_s)
entry;
uint64_t id; /* object id (search key) */
/* references on the Lua registry */
int ref; /* the correspoding userdata */
void *mem; /* userdata memory area allocated and released by Lua */
const char *mt;
};
#define UNEXPECTED_ERROR "unexpected error (%s, %d)", __FILE__, __LINE__
static int cmp(udata_t *udata1, udata_t *udata2) /* the compare function */
{
return (udata1->id < udata2->id ? -1 : udata1->id > udata2->id);
}
static RB_HEAD(udatatree_s, udata_s) Head = RB_INITIALIZER(&Head);
RB_PROTOTYPE_STATIC(udatatree_s, udata_s, entry, cmp)
RB_GENERATE_STATIC(udatatree_s, udata_s, entry, cmp)
static udata_t *udata_remove(udata_t *udata)
{
return RB_REMOVE(udatatree_s, &Head, udata);
}
static udata_t *udata_insert(udata_t *udata)
{
return RB_INSERT(udatatree_s, &Head, udata);
}
static udata_t *udata_search(uint64_t id)
{
udata_t tmp;
tmp.id = id;
return RB_FIND(udatatree_s, &Head, &tmp);
}
static udata_t *udata_first(uint64_t id)
{
udata_t tmp;
tmp.id = id;
return RB_NFIND(udatatree_s, &Head, &tmp);
}
#if 0
static udata_t *udata_next(udata_t *udata)
{ return RB_NEXT(udatatree_s, &Head, udata); }
static udata_t *udata_prev(udata_t *udata)
{ return RB_PREV(udatatree_s, &Head, udata); }
static udata_t *udata_min(void)
{ return RB_MIN(udatatree_s, &Head); }
static udata_t *udata_max(void)
{ return RB_MAX(udatatree_s, &Head); }
static udata_t *udata_root(void)
{ return RB_ROOT(&Head); }
#endif
void *udata_new(lua_State *L, size_t size, uint64_t id_, const char *mt)
/* Creates a new Lua userdata, optionally sets its metatable to mt (if != NULL),
* associates the userdata with the passed id and pushes the userdata on the stack.
*
* The userdata can be subsquently pushed on the Lua stack with udata_push(L, id).
* (This is useful to bind C/C++ objects to Lua userdata).
*
* If id=0, the pointer to the memory area allocated by Lua is used as identifier
* (this function returnes it).
*/
{
udata_t *udata;
if ((udata = (udata_t *)Malloc(L, sizeof(udata_t))) == NULL)
{
luaL_error(L, "cannot allocate memory");
return NULL;
}
memset(udata, 0, sizeof(udata_t));
udata->mem = lua_newuserdata(L, size);
if (!udata->mem)
{
Free(L, udata);
luaL_error(L, "lua_newuserdata error");
return NULL;
}
udata->id = id_ != 0 ? id_ : (uint64_t)(uintptr_t)(udata->mem);
if (udata_search(udata->id))
{
Free(L, udata);
luaL_error(L, "duplicated object %I", id_);
return NULL;
}
/* create a reference for later push's */
lua_pushvalue(L, -1); /* the newly created userdata */
udata->ref = luaL_ref(L, LUA_REGISTRYINDEX);
udata_insert(udata);
if (mt)
{
udata->mt = mt;
luaL_getmetatable(L, mt);
lua_setmetatable(L, -2);
}
return udata->mem;
}
void *udata_mem(uint64_t id)
{
udata_t *udata = udata_search(id);
return udata ? udata->mem : NULL;
}
int udata_unref(lua_State *L, uint64_t id)
/* unreference udata so that it will be garbage collected */
{
// printf("unref object %lu\n", id);
udata_t *udata = udata_search(id);
if (!udata)
return luaL_error(L, "invalid object identifier %p", id);
if (udata->ref != LUA_NOREF)
{
luaL_unref(L, LUA_REGISTRYINDEX, udata->ref);
udata->ref = LUA_NOREF;
}
return 0;
}
int udata_free(lua_State *L, uint64_t id)
/* this should be called in the __gc metamethod
*/
{
udata_t *udata = udata_search(id);
// printf("free object %lu\n", id);
if (!udata)
return luaL_error(L, "invalid object identifier %p", id);
/* release all references */
if (udata->ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, udata->ref);
udata_remove(udata);
Free(L, udata);
/* mem is released by Lua at garbage collection */
return 0;
}
int udata_push(lua_State *L, uint64_t id)
{
udata_t *udata = udata_search(id);
if (!udata)
return luaL_error(L, "invalid object identifier %p", id);
if (udata->ref == LUA_NOREF)
return luaL_error(L, "unreferenced object");
if (lua_rawgeti(L, LUA_REGISTRYINDEX, udata->ref) != LUA_TUSERDATA)
return luaL_error(L, UNEXPECTED_ERROR);
return 1; /* one value pushed */
}
void udata_free_all(lua_State *L)
/* free all without unreferencing (for atexit()) */
{
udata_t *udata;
while ((udata = udata_first(0)))
{
udata_remove(udata);
Free(L, udata);
}
}
int udata_scan(lua_State *L, const char *mt,
void *info, int (*func)(lua_State *L, const void *mem, const char *mt, const void *info))
/* scans the udata database, and calls the func callback for every 'mt' object found
* (the object may be deleted in the callback).
* func must return 0 to continue the scan, !=0 to interrupt it.
* returns 1 if interrupted, 0 otherwise
*/
{
int stop = 0;
uint64_t id = 0;
udata_t *udata;
while ((udata = udata_first(id)))
{
id = udata->id + 1;
if (mt == udata->mt)
{
stop = func(L, (const void *)(udata->mem), mt, info);
if (stop)
return 1;
}
}
return 0;
}
static int is_subclass(lua_State *L, int arg, int mt_index)
{
int ok;
if (luaL_getmetafield(L, arg, "__index") == LUA_TNIL)
return 0;
if (lua_rawequal(L, mt_index, lua_gettop(L)))
{
lua_pop(L, 1);
return 1;
}
ok = is_subclass(L, lua_gettop(L), mt_index);
lua_pop(L, 1);
return ok;
}
void *udata_test(lua_State *L, int arg, const char *mt)
/* same as luaL_testudata(), but succeeds also if the userdata has not
* mt as metatable but as ancestor
*/
{
void *mem;
int ok;
if ((mem = luaL_testudata(L, arg, mt)))
return mem;
if ((mem = lua_touserdata(L, arg)) == NULL)
return NULL;
if (luaL_getmetatable(L, mt) != LUA_TTABLE)
{
luaL_error(L, "cannot find metatable '%s'", mt);
return NULL;
}
ok = is_subclass(L, arg, lua_gettop(L));
lua_pop(L, 1);
return ok ? mem : NULL;
}
/*------------------------------------------------------------------------------*
| newmetatable for 'class' userdata |
*------------------------------------------------------------------------------*/
int udata_define(lua_State *L, const char *mt, const luaL_Reg *methods, const luaL_Reg *metamethods)
{
/* create the metatable */
if (!luaL_newmetatable(L, mt))
return luaL_error(L, "cannot create metatable '%s'", mt);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
if (metamethods)
/* add metamethods */
luaL_setfuncs(L, metamethods, 0);
if (methods)
{
/* add methods */
luaL_getsubtable(L, -1, "__index");
luaL_setfuncs(L, methods, 0);
lua_pop(L, 1);
}
lua_pop(L, 1);
return 0;
}
int udata_inherit(lua_State *L, const char *sub, const char *super)
/* Sets metatable(sub).__index = metatable(super)
*
* This way, if one accesses a field/method of a 'sub' object which is not defined in
* the 'sub' metatable, Lua searches for it in the 'super' metatable (i.e., the 'sub'
* type inherits from 'super').
*/
{
if (luaL_getmetatable(L, sub) != LUA_TTABLE)
return luaL_error(L, "cannot find metatable '%s'", sub);
luaL_getsubtable(L, -1, "__index");
if (luaL_getmetatable(L, super) != LUA_TTABLE)
return luaL_error(L, "cannot find metatable '%s'", super);
lua_setmetatable(L, -2);
lua_pop(L, 2);
return 0;
}
int udata_addmethods(lua_State *L, const char *mt, const luaL_Reg *methods)
/* Adds methods to the metatable mt */
{
if (luaL_getmetatable(L, mt) != LUA_TTABLE)
return luaL_error(L, "cannot find metatable '%s'", mt);
if (methods)
{
/* add methods */
luaL_getsubtable(L, -1, "__index");
luaL_setfuncs(L, methods, 0);
lua_pop(L, 1);
}
lua_pop(L, 1);
return 0;
}

@ -1,72 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include "lua.h"
#include "lauxlib.h"
#ifndef Malloc
#define Malloc moonccd_Malloc
void *Malloc(lua_State *L, size_t size);
#define Free moonccd_Free
void Free(lua_State *L, void *ptr);
#endif
#define udata_t moonccd_udata_t
#define udata_s moonccd_udata_s
#define moonccd_udata_t struct moonccd_udata_s
#define udata_new moonccd_udata_new
void *udata_new(lua_State *, size_t, uint64_t, const char *);
#define udata_unref moonccd_udata_unref
int udata_unref(lua_State *L, uint64_t);
#define udata_free moonccd_udata_free
int udata_free(lua_State *, uint64_t);
#define udata_mem moonccd_udata_mem
void *udata_mem(uint64_t);
#define udata_push moonccd_udata_push
int udata_push(lua_State *, uint64_t);
#define udata_free_all moonccd_udata_free_all
void udata_free_all(lua_State *L);
#define udata_scan moonccd_udata_scan
int udata_scan(lua_State *L, const char *mt,
void *info, int (*func)(lua_State *L, const void *mem, const char *mt, const void *info));
#define udata_define moonccd_udata_define
int udata_define(lua_State *, const char *, const luaL_Reg *, const luaL_Reg *);
#define udata_inherit moonccd_udata_inherit
int udata_inherit(lua_State *, const char *, const char *);
#define udata_test moonccd_udata_test
void *udata_test(lua_State *, int, const char *);
#define udata_addmethods moonccd_udata_addmethods
int udata_addmethods(lua_State *, const char *, const luaL_Reg *);
#ifdef __cplusplus
}
#endif

@ -1,410 +0,0 @@
/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
/*------------------------------------------------------------------------------*
| Misc utilities |
*------------------------------------------------------------------------------*/
int noprintf(const char *fmt, ...)
{
(void)fmt;
return 0;
}
int notavailable(lua_State *L, ...)
{
return luaL_error(L, "function not available in this CL version");
}
/*------------------------------------------------------------------------------*
| Malloc |
*------------------------------------------------------------------------------*/
/* We do not use malloc(), free() etc directly. Instead, we inherit the memory
* allocator from the main Lua state instead (see lua_getallocf in the Lua manual)
* and use that.
*
* By doing so, we can use an alternative malloc() implementation without recompiling
* this library (we have needs to recompile lua only, or execute it with LD_PRELOAD
* set to the path to the malloc library we want to use).
*/
static lua_Alloc Alloc = NULL;
static void *AllocUd = NULL;
static void malloc_init(lua_State *L)
{
if (Alloc)
unexpected(L);
Alloc = lua_getallocf(L, &AllocUd);
}
static void *Malloc_(size_t size)
{
return Alloc ? Alloc(AllocUd, NULL, 0, size) : NULL;
}
static void Free_(void *ptr)
{
if (Alloc)
Alloc(AllocUd, ptr, 0, 0);
}
void *Malloc(lua_State *L, size_t size)
{
void *ptr;
if (size == 0)
{
luaL_error(L, errstring(ERR_MALLOC_ZERO));
return NULL;
}
ptr = Malloc_(size);
if (ptr == NULL)
{
luaL_error(L, errstring(ERR_MEMORY));
return NULL;
}
memset(ptr, 0, size);
//DBG("Malloc %p\n", ptr);
return ptr;
}
void *MallocNoErr(lua_State *L, size_t size) /* do not raise errors (check the retval) */
{
void *ptr = Malloc_(size);
(void)L;
if (ptr == NULL)
return NULL;
memset(ptr, 0, size);
//DBG("MallocNoErr %p\n", ptr);
return ptr;
}
char *Strdup(lua_State *L, const char *s)
{
size_t len = strnlen(s, 256);
char *ptr = (char *)Malloc(L, len + 1);
if (len > 0)
memcpy(ptr, s, len);
ptr[len] = '\0';
return ptr;
}
void Free(lua_State *L, void *ptr)
{
(void)L;
//DBG("Free %p\n", ptr);
if (ptr)
Free_(ptr);
}
/*------------------------------------------------------------------------------*
| Time utilities |
*------------------------------------------------------------------------------*/
#if defined(LINUX)
#if 0
static double tstosec(const struct timespec *ts)
{
return ts->tv_sec*1.0+ts->tv_nsec*1.0e-9;
}
#endif
static void sectots(struct timespec *ts, double seconds)
{
ts->tv_sec = (time_t)seconds;
ts->tv_nsec = (long)((seconds - ((double)ts->tv_sec)) * 1.0e9);
}
double now(void)
{
#if _POSIX_C_SOURCE >= 199309L
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
{
printf("clock_gettime error\n");
return -1;
}
return ts.tv_sec + ts.tv_nsec * 1.0e-9;
#else
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
{
printf("gettimeofday error\n");
return -1;
}
return tv.tv_sec + tv.tv_usec * 1.0e-6;
#endif
}
void sleeep(double seconds)
{
#if _POSIX_C_SOURCE >= 199309L
struct timespec ts, ts1;
struct timespec *req, *rem, *tmp;
sectots(&ts, seconds);
req = &ts;
rem = &ts1;
while (1)
{
if (nanosleep(req, rem) == 0)
return;
tmp = req;
req = rem;
rem = tmp;
}
#else
usleep((useconds_t)(seconds * 1.0e6));
#endif
}
#define time_init(L) \
do \
{ \
(void)L; /* do nothing */ \
} while (0)
#elif defined(MINGW)
#include <windows.h>
static LARGE_INTEGER Frequency;
double now(void)
{
LARGE_INTEGER ts;
QueryPerformanceCounter(&ts);
return ((double)(ts.QuadPart)) / Frequency.QuadPart;
}
void sleeep(double seconds)
{
DWORD msec = (DWORD)seconds * 1000;
//if(msec < 0) return; DWORD seems to be unsigned
Sleep(msec);
}
static void time_init(lua_State *L)
{
(void)L;
QueryPerformanceFrequency(&Frequency);
}
#endif
/*------------------------------------------------------------------------------*
| Light userdata |
*------------------------------------------------------------------------------*/
void *checklightuserdata(lua_State *L, int arg)
{
if (lua_type(L, arg) != LUA_TLIGHTUSERDATA)
{
luaL_argerror(L, arg, "expected lightuserdata");
return NULL;
}
return lua_touserdata(L, arg);
}
void *optlightuserdata(lua_State *L, int arg)
{
if (lua_isnoneornil(L, arg))
return NULL;
return checklightuserdata(L, arg);
}
void *checklightuserdataorzero(lua_State *L, int arg)
{
int val, isnum;
val = lua_tointegerx(L, arg, &isnum);
if (!isnum)
return checklightuserdata(L, arg);
if (val != 0)
luaL_argerror(L, arg, "expected lightuserdata or 0");
return NULL;
}
/*------------------------------------------------------------------------------*
| Deep copy of a table |
*------------------------------------------------------------------------------*/
int copytable(lua_State *L)
/* Deep-copies the contents of the table at arg=-1 to the table at arg=-2
* Leaves them on the stack.
*/
{
int src = lua_gettop(L);
int dst = src - 1;
lua_pushnil(L);
while (lua_next(L, src))
{
lua_pushvalue(L, -2); // key
if (lua_type(L, -1) == LUA_TTABLE) /* nested */
{
lua_newtable(L); //dst
lua_pushvalue(L, -3); // value
copytable(L);
lua_pop(L, 1);
}
else
lua_pushvalue(L, -2); // value
lua_rawset(L, dst);
lua_pop(L, 1); // value
}
return 0;
}
/*------------------------------------------------------------------------------*
| Custom luaL_checkxxx() style functions |
*------------------------------------------------------------------------------*/
int checkboolean(lua_State *L, int arg)
{
if (!lua_isboolean(L, arg))
return (int)luaL_argerror(L, arg, "boolean expected");
return lua_toboolean(L, arg); // ? 1 : 0;
}
int testboolean(lua_State *L, int arg, int *err)
{
if (!lua_isboolean(L, arg))
{
*err = ERR_TYPE;
return 0;
}
*err = 0;
return lua_toboolean(L, arg); // ? 1 : 0;
}
int optboolean(lua_State *L, int arg, int d)
{
if (!lua_isboolean(L, arg))
return d;
return lua_toboolean(L, arg);
}
/* 1-based index to 0-based ------------------------------------------*/
int testindex(lua_State *L, int arg, int *err)
{
int val;
if (!lua_isinteger(L, arg))
{
*err = ERR_TYPE;
return 0;
}
val = lua_tointeger(L, arg);
if (val < 1)
{
*err = ERR_GENERIC;
return 0;
}
*err = 0;
return val - 1;
}
int checkindex(lua_State *L, int arg)
{
int val = luaL_checkinteger(L, arg);
if (val < 1)
return luaL_argerror(L, arg, "positive integer expected");
return val - 1;
}
int optindex(lua_State *L, int arg, int optval /* 0-based */)
{
int val = luaL_optinteger(L, arg, optval + 1);
if (val < 1)
return luaL_argerror(L, arg, "positive integer expected");
return val - 1;
}
void pushindex(lua_State *L, int val)
{
lua_pushinteger((L), (val) + 1);
}
/*------------------------------------------------------------------------------*
| Internal error codes |
*------------------------------------------------------------------------------*/
const char *errstring(int err)
{
switch (err)
{
case ERR_NOTPRESENT:
return "missing";
case ERR_SUCCESS:
return "success";
case ERR_GENERIC:
return "generic error";
case ERR_TABLE:
return "not a table";
case ERR_FUNCTION:
return "not a function";
case ERR_EMPTY:
return "empty list";
case ERR_TYPE:
return "invalid type";
case ERR_ELEMTYPE:
return "invalid element type";
case ERR_VALUE:
return "invalid value";
case ERR_ELEMVALUE:
return "invalid element value";
case ERR_MEMORY:
return "out of memory";
case ERR_MALLOC_ZERO:
return "zero bytes malloc";
case ERR_LENGTH:
return "invalid length";
case ERR_POOL:
return "elements are not from the same pool";
case ERR_BOUNDARIES:
return "invalid boundaries";
case ERR_RANGE:
return "out of range";
case ERR_FOPEN:
return "cannot open file";
case ERR_OPERATION:
return "operation failed";
case ERR_UNKNOWN:
return "unknown field name";
default:
return "???";
}
return NULL; /* unreachable */
}
/*------------------------------------------------------------------------------*
| Inits |
*------------------------------------------------------------------------------*/
void moonccd_utils_init(lua_State *L)
{
malloc_init(L);
time_init(L);
}

File diff suppressed because it is too large Load Diff

@ -1,163 +0,0 @@
#ifndef lua_ecs_cdata_h
#define lua_ecs_cdata_h
#include <assert.h>
struct entity_world;
struct ecs_capi
{
void *(*iter)(struct entity_world *w, int cid, int index);
void (*clear_type)(struct entity_world *w, int cid);
int (*sibling_id)(struct entity_world *w, int cid, int index, int slibling_id);
void *(*add_sibling)(struct entity_world *w, int cid, int index, int slibling_id, const void *buffer, void *L, int world_index);
int (*new_entity)(struct entity_world *w, int cid, const void *buffer, void *L, int world_index);
void (*remove)(struct entity_world *w, int cid, int index, void *L, int world_index);
void (*enable_tag)(struct entity_world *w, int cid, int index, int tag_id, void *L, int world_index);
void (*disable_tag)(struct entity_world *w, int cid, int index, int tag_id);
void *(*iter_lua)(struct entity_world *w, int cid, int index, void *L, int world_index);
int (*assign_lua)(struct entity_world *w, int cid, int index, void *L, int world_index);
};
struct ecs_context
{
struct ecs_capi *api;
struct entity_world *world;
void *L; // for memory allocator
int max_id;
int cid[1];
};
static inline void
check_id_(struct ecs_context *ctx, int cid)
{
assert(cid >= 0 && cid <= ctx->max_id);
}
static inline void *
entity_iter(struct ecs_context *ctx, int cid, int index)
{
check_id_(ctx, cid);
return ctx->api->iter(ctx->world, ctx->cid[cid], index);
}
static inline void *
entity_ref_object(struct ecs_context *ctx, int cid, int index)
{
if (index <= 0)
return NULL;
check_id_(ctx, cid);
return ctx->api->iter_lua(ctx->world, ctx->cid[cid], index - 1, ctx->L, 1);
}
static inline void
entity_clear_type(struct ecs_context *ctx, int cid)
{
check_id_(ctx, cid);
ctx->api->clear_type(ctx->world, ctx->cid[cid]);
}
static inline int
entity_sibling_id(struct ecs_context *ctx, int cid, int index, int sibling_id)
{
check_id_(ctx, cid);
check_id_(ctx, sibling_id);
return ctx->api->sibling_id(ctx->world, ctx->cid[cid], index, ctx->cid[sibling_id]);
}
static inline void *
entity_sibling(struct ecs_context *ctx, int cid, int index, int sibling_id)
{
check_id_(ctx, cid);
check_id_(ctx, sibling_id);
int id = ctx->api->sibling_id(ctx->world, ctx->cid[cid], index, ctx->cid[sibling_id]);
if (id == 0)
{
return NULL;
}
else
{
return ctx->api->iter(ctx->world, ctx->cid[sibling_id], id - 1);
}
}
static inline void *
entity_add_sibling(struct ecs_context *ctx, int cid, int index, int sibling_id, const void *buffer)
{
check_id_(ctx, cid);
check_id_(ctx, sibling_id);
return ctx->api->add_sibling(ctx->world, ctx->cid[cid], index, ctx->cid[sibling_id], buffer, ctx->L, 1);
}
static inline int
entity_new(struct ecs_context *ctx, int cid, const void *buffer)
{
check_id_(ctx, cid);
return ctx->api->new_entity(ctx->world, ctx->cid[cid], buffer, ctx->L, 1);
}
static inline void
entity_remove(struct ecs_context *ctx, int cid, int index)
{
check_id_(ctx, cid);
ctx->api->remove(ctx->world, ctx->cid[cid], index, ctx->L, 1);
}
static inline void
entity_enable_tag(struct ecs_context *ctx, int cid, int index, int tag_id)
{
check_id_(ctx, cid);
check_id_(ctx, tag_id);
ctx->api->enable_tag(ctx->world, ctx->cid[cid], index, ctx->cid[tag_id], ctx->L, 1);
}
static inline void
entity_disable_tag(struct ecs_context *ctx, int cid, int index, int tag_id)
{
check_id_(ctx, cid);
check_id_(ctx, tag_id);
ctx->api->disable_tag(ctx->world, ctx->cid[cid], index, ctx->cid[tag_id]);
}
static inline int
entity_assign_lua(struct ecs_context *ctx, int cid, int index)
{
check_id_(ctx, cid);
assert(index > 0);
return ctx->api->assign_lua(ctx->world, ctx->cid[cid], index - 1, ctx->L, 1);
}
static inline int
entity_new_ref(struct ecs_context *ctx, int cid)
{
check_id_(ctx, cid);
int object_id = ctx->cid[cid];
int dead_tag = object_id + 1;
int id;
if (ctx->api->iter(ctx->world, dead_tag, 0))
{
// reuse
id = ctx->api->sibling_id(ctx->world, dead_tag, 0, object_id);
assert(id > 0);
--id;
ctx->api->disable_tag(ctx->world, dead_tag, 0, dead_tag);
}
else
{
id = ctx->api->new_entity(ctx->world, object_id, NULL, ctx->L, 1);
}
return id + 1;
}
static inline void
entity_release_ref(struct ecs_context *ctx, int cid, int id)
{
if (id == 0)
return;
check_id_(ctx, cid);
int object_id = ctx->cid[cid];
int dead_tag = object_id + 1;
ctx->api->enable_tag(ctx->world, object_id, id - 1, dead_tag, ctx->L, 1);
}
#endif

@ -1,234 +0,0 @@
local ecs = require "ecs"
local N = 1
local w = ecs.world()
print("memory:", w:memory())
w:register {
name = "vector",
"x:float",
"y:float",
}
w:register {
name = "mark"
}
w:register {
name = "id",
type = "int"
}
w:register {
name = "object",
type = "lua",
}
local t = {}
for i = 1, N do
w:new {
vector = {
x = 1,
y = 2,
}
}
t[i] = { x = 1, y = 2 }
end
w:update()
local function swap_c()
for v in w:select "vector:update" do
local vec = v.vector
vec.x, vec.y = vec.y, vec.x
end
end
local function swap_lua()
for _, v in ipairs(t) do
v.x, v.y = v.y, v.x
end
end
local function timing(f)
local c = os.clock()
for i = 1, 100 do
f()
end
return os.clock() - c
end
print("memory:", w:memory())
print("CSWAP", timing(swap_c))
print("LUASWAP", timing(swap_lua))
w:new {
vector = {
x = 3,
y = 4,
},
id = 100,
}
table.insert(t, { x = 3, y = 4 })
w:new {
vector = {
x = 5,
y = 6,
},
mark = true,
}
table.insert(t, { x = 5, y = 6 })
w:update()
w:register {
name = "singleton",
type = "lua"
}
local context = w:context {
"vector",
"mark",
"id",
"singleton",
}
w:new { singleton = "Hello World" }
w:update()
local test = require "ecs.ctest"
print(test.get(context))
local function csum()
return test.sum(context)
end
print("csum = ", csum())
local function luasum()
local s = 0
for v in w:select "vector:in" do
s = s + v.vector.x + v.vector.y
end
return s
end
print("luasum = ", luasum())
local function luanativesum()
local s = 0
for _, v in ipairs(t) do
s = s + v.x + v.y
end
return s
end
print("lnative sum = ", luanativesum())
print("CSUM", timing(csum))
print("LUASUM", timing(luasum))
print("LNATIVESUM", timing(luanativesum))
print "vector:update"
for v in w:select "vector:update" do
local vec = v.vector
print(vec.x, vec.y)
vec.x, vec.y = vec.y , vec.x
end
print "vector:in id?out"
for v in w:select "vector:in id?out" do
print(v.vector.x, v.vector.y, v.id)
if v.id then
v.id = 200
end
end
print "vector:in id:in"
for v in w:select "vector:in id:in" do
print(v.vector.x, v.vector.y, v.id)
end
w:new { object = "Hello" , mark = true }
w:new { object = "World" , mark = true }
w:update()
print "mark:update object:in"
for v in w:select "mark:update object:in" do
print(v.object)
if v.object == "World" then
print "Disable mark where object == World"
v.mark = false
end
end
print "mark:exist object:in"
for v in w:select "mark:exist object:in" do
print(v.object)
end
for v in w:select "object:exist mark:out" do
v.mark = false
end
for v in w:select "mark:exist" do
print("Remove")
w:remove(v)
end
for v in w:select "REMOVED:exist vector:in" do
print(v.vector.x, v.vector.y, "removed")
end
w:update() -- remove all
local n = 0
for v in w:select "mark:in" do
n = n + 1
end
print("Marked", n)
print "object:update"
for v in w:select "object:update" do
print(v.object)
v.object = v.object .. " world"
end
print "object:in"
for v in w:select "object:in" do
print(v.object)
end
w:register {
name = "sum",
type = "float",
}
for v in w:select "vector:in sum:new" do
print(v.vector.x, "+", v.vector.y)
v.sum = v.vector.x + v.vector.y
end
for v in w:select "sum:in" do
print(v.sum)
end
w:clear "sum"
for v in w:select "sum:exist" do
error "Not empty"
end

@ -1,39 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "key",
type = "int",
}
w:register {
name = "temp",
type = "lua",
}
for i = 1, 10 do
w:new { key = i }
end
local function add_temp(i)
for v in w:select "key:in temp?new" do
if v.key == i then
v.temp = "Temp"
end
end
end
local function print_entity()
for v in w:select "key:in temp:in" do
print(v.key, v.temp)
end
end
add_temp(5)
print_entity()
add_temp(6)
print_entity()
assert(pcall(add_temp, 4) == false)

@ -1,55 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "order",
order = true,
}
w:register {
name = "node",
"id:int",
"parent:int",
}
w:new {
node = { id = 1, parent = 0 } ,
order = true,
}
w:new {
node = { id = 2, parent = 0 },
order = true,
}
w:new {
node = { id = 0, parent = -1 },
}
w:new {
node = { id = 3, parent = 0 },
order = true,
}
for v in w:select "node:in order?new" do
assert(v.order == nil)
if v.node.parent < 0 then
-- add order
v.order = true
end
end
local cache = {}
for v in w:select "order node:update" do
local node = v.node
if node.parent < 0 or cache[node.parent] then
cache[node.id] = true
print(node.id, node.parent)
else
v.order = false
end
end
assert(pcall(w.select, w, "node order") == false)

@ -1,53 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "value",
type = "int",
}
local r = {}
for i=1, 42 do
r[i] = {}
w:new {
value = i,
reference = r[i],
}
w:new {
value = -i,
}
end
for v in w:select("value:in") do
print(v.value)
if v.value < 0 then
w:remove(v)
end
end
local function read(i)
local v = w:sync("value:in", r[i])
return v.value
end
w:update()
w:remove(r[1])
w:remove(r[10])
w:remove(r[20])
w:remove(r[30])
w:remove_reference(r[40])
w:update()
for i=1,42 do
print(pcall(read,i))
end
for v in w:select("value:in") do
print(v.value)
end

@ -1,31 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "value",
type = "int",
}
w:register {
name = "mark"
}
w:new {
value = 1,
mark = true,
}
w:new {
mark = true,
}
for v in w:select "mark" do
w:sync("value?in", v)
print(v.value)
end
for v in w:select "mark" do
print(pcall(w.sync, w, "value:in", v))
end

@ -1,55 +0,0 @@
-- test object
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "refobject",
type = "int",
ref = true,
}
local id1 = w:ref("refobject", { refobject = 42 })
local id2 = w:ref("refobject", { refobject = 0 })
local id3 = w:ref("refobject", { refobject = 100 })
print ("New", id1, id2, id3)
print(w:object("refobject", id1))
print("Release", id1)
w:release("refobject", id1)
for v in w:select "refobject:in" do
print(v.refobject)
end
local id4 = w:ref("refobject", { refobject = -42 })
print ("New", id4)
print ("Release", id2)
w:release("refobject", id2)
print ("Release", id3)
w:release("refobject", id3)
print "List refobject"
for v in w:select "refobject:in" do
print(v.refobject)
end
w:register {
name = "index",
type = "int",
}
w:new {
index = id4
}
for v in w:select "index:in" do
print(v.index)
end

@ -1,51 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "a",
type = "int",
}
w:register {
name = "b",
type = "float",
}
for i = 1, 20 do
w:new { a = i }
w:new { b = i }
end
for i = 20, 40 do
w:new { a = i , b = i }
end
w:update()
for v in w:select "a:in" do
if v.a % 2 == 1 then
w:remove(v)
end
end
for v in w:select "b:in" do
if v.b < 10 then
w:remove(v)
end
end
for v in w:select "REMOVED a?in b?in" do
print(v.a, v.b, "Removed")
end
w:update()
for v in w:select "a:in" do
print(v.a)
end
for v in w:select "b:in" do
print(v.b)
end

@ -1,29 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "a",
type = "int",
}
w:register {
name = "temp",
type = "int",
}
for i = 1, 10 do
w:new { a = i }
end
for v in w:select "a:in" do
if v.a %2 == 0 then
v.a = -v.a
v.temp = 42
w:sync("a:out temp:new", v)
end
end
for v in w:select "a:in temp?in" do
print(v.a, v.temp)
end

@ -1,62 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "t",
"a:bool",
"b:userdata",
}
w:register {
name = "flag",
}
w:new {
t = {
a = false,
b = ecs.NULL,
}
}
local function print_v()
local v = w:singleton("t", "t:in")
print(".a = ",v.t.a)
print(".b = ",v.t.b)
local v = w:singleton "t"
w:sync("t:in", v)
print(".a = ", v.t.a)
print(".a = ", v.t.b)
end
local ctx = w:context { "t" }
print("ctx = ", ctx)
local test = require "ecs.ctest"
print_v()
test.testuserdata(ctx)
print_v()
local v = w:singleton("t", "flag t:in")
assert(v == nil)
-- remove singleton of t
local v = w:singleton "t"
w:remove(v)
w:update()
w:new {
t = {
a = true,
b = ecs.NULL,
},
flag = true,
}
local v = w:singleton("t", "flag t:in")
assert(v.t.a == true)

@ -1,19 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "object",
type = "int",
ref = true,
}
for i = 1, 10 do
w:ref("object", { object = i * 10 })
end
w:order("order", "object", { 9,7,5,3,1 })
for v in w:select "order object:in" do
print(v.object)
end

@ -1,33 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "v",
type = "int",
}
w:register {
name = "marked"
}
for i = 1, 10 do
w:new {
v = i,
marked = i % 2 == 1,
}
end
for v in w:select "v:in marked?in" do
print(v.v, v.marked)
end
print "Marked"
for v in w:select "v:in marked" do
print(v.v)
end
print "Not Marked"
for v in w:select "v:in marked:absent" do
print(v.v)
end

@ -1,52 +0,0 @@
local ecs = require "ecs"
local w = ecs.world()
w:register {
name = "vector",
"x:float",
"y:float",
}
w:register {
name = "text",
type = "lua",
}
w:register {
name = "mark"
}
w:register {
name = "index",
type = "int",
}
w:new {
vector = { x = 1, y = 2 },
text = "Hello World",
mark = true,
index = 2,
}
w:new {
text = "Hello World 2",
mark = true,
index = 1,
}
for v in w:select "mark" do
w:readall(v)
for k,v in pairs(v) do
print(k,v)
end
end
local ids = w:dumpid "index"
for idx, id in ipairs(ids) do
print(idx, id)
end

@ -1,89 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
#include "rc4.h"
#include <stdlib.h>
#define RC4_METATABLE "rc4_metatable"
#define RC4_BUFSIZE (4096) /* after wrap in lua string, is 4096 */
static int
lrc4(lua_State * L) {
size_t len;
const char * key = luaL_checklstring(L, 1, &len);
#if LUA_VERSION_NUM == 504
struct rc4_state * rc4 = (struct rc4_state *)lua_newuserdatauv(L, sizeof(*rc4), 0);
#else
struct rc4_state * rc4 = (struct rc4_state *)lua_newuserdata(L, sizeof(*rc4));
#endif
lua_pushvalue(L, 1);
lua_setuservalue(L, -2);
luaL_getmetatable(L, RC4_METATABLE);
lua_setmetatable(L, -2);
librc4_init(rc4, (uint8_t*)key, (int)len);
return 1;
}
static int
lreset(lua_State* L) {
size_t len;
struct rc4_state * rc4 = (struct rc4_state *)luaL_checkudata(L, 1, RC4_METATABLE);
lua_getuservalue(L, 1);
const char* key = luaL_checklstring(L, -1, &len);
librc4_init(rc4, (uint8_t*)key, (int)len);
return 0;
}
static int
lcrypt(lua_State * L) {
struct rc4_state * rc4 = (struct rc4_state *)luaL_checkudata(L, 1, RC4_METATABLE);
size_t len;
const char * data = luaL_checklstring(L, 2, &len);
uint8_t *buffer = (uint8_t *)malloc(len);
if(buffer) {
librc4_crypt(rc4, (const uint8_t*)data, buffer, (int)len);
lua_pushlstring(L, (const char*)buffer, len);
free(buffer);
return 1;
}
return 0;
}
int
luaopen_rc4_c(lua_State *L) {
luaL_checkversion(L);
if (luaL_newmetatable(L, RC4_METATABLE)) {
luaL_Reg rc4_mt[] = {
{ "crypt", lcrypt },
{ "reset", lreset },
{ NULL, NULL },
};
luaL_newlib(L, rc4_mt);
lua_setfield(L, -2, "__index");
}
lua_pop(L, 1);
luaL_Reg l[] = {
{ "rc4", lrc4 },
{ NULL, NULL },
};
luaL_newlib(L, l);
lua_pushinteger(L, 2);
lua_setfield(L, -2, "VERSION");
return 1;
}

@ -1,99 +0,0 @@
/*
* rc4.c
*
* Copyright (c) 1996-2000 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* $FreeBSD: src/sys/crypto/rc4/rc4.c,v 1.2.2.1 2000/04/18 04:48:31 archie Exp $
*/
#include <stdint.h>
#include "rc4.h"
static __inline void
swap_bytes(uint8_t *a, uint8_t *b)
{
uint8_t temp;
temp = *a;
*a = *b;
*b = temp;
}
/*
* Initialize an RC4 state buffer using the supplied key,
* which can have arbitrary length.
*/
void
librc4_init(struct rc4_state *const state, const uint8_t *key, int keylen)
{
uint8_t j;
int i, k;
/* Initialize state with identity permutation */
for (i = 0; i < 256; i++)
state->perm[i] = (uint8_t)i;
state->index1 = 0;
state->index2 = 0;
/* Randomize the permutation using key data */
for (j = i = k = 0; i < 256; i++) {
j += state->perm[i] + key[k];
swap_bytes(&state->perm[i], &state->perm[j]);
if (++k >= keylen)
k = 0;
}
}
/*
* Encrypt some data using the supplied RC4 state buffer.
* The input and output buffers may be the same buffer.
* Since RC4 is a stream cypher, this function is used
* for both encryption and decryption.
*/
void
librc4_crypt(struct rc4_state *const state, const uint8_t *inbuf, uint8_t *outbuf, int buflen)
{
int i;
uint8_t j;
for (i = 0; i < buflen; i++) {
/* Update modification indicies */
state->index1++;
state->index2 += state->perm[state->index1];
/* Modify permutation */
swap_bytes(&state->perm[state->index1], &state->perm[state->index2]);
/* Encrypt/decrypt next byte */
j = state->perm[state->index1] + state->perm[state->index2];
outbuf[i] = inbuf[i] ^ state->perm[j];
}
}

@ -1,51 +0,0 @@
/*
* rc4.h
*
* Copyright (c) 1996-2000 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* $FreeBSD: src/sys/crypto/rc4/rc4.h,v 1.2.2.1 2000/04/18 04:48:32 archie Exp $
*/
#ifndef _SYS_CRYPTO_RC4_RC4_H_
#define _SYS_CRYPTO_RC4_RC4_H_
struct rc4_state {
uint8_t perm[256];
uint8_t index1;
uint8_t index2;
};
void librc4_init(struct rc4_state *state, const uint8_t *key, int keylen);
void librc4_crypt(struct rc4_state *state, const uint8_t *inbuf, uint8_t *outbuf, int buflen);
#endif

@ -1,53 +0,0 @@
local rc4 = require "rc4.c"
local function gen_key(t)
local len = #t
for i = 1, len do
local b = t[i]
local c = string.char(b)
t[i] = c
end
local key = table.concat(t)
return rc4.rc4(key)
end
local decode_key = gen_key {
215,100,200,204,233,50,85,196,71,141,
122,160,93,131,243,234,162,183,36,155,
4,62,35,205,40,102,33,27,255,55,
131,214,156,75,163,134,126,249,74,197,
134,197,102,228,72,90,206,235,17,243,
134,22,49,169,227,89,16,5,117,16,
60,248,230,217,68,138,96,194,131,170,
136,10,112,238,238,184,72,189,163,90,
176,42,112,225,212,84,58,228,89,175,
244,150,168,219,112,236,101,208,175,233,
123,55,243,235,37,225,164,110,158,71,
201,78,114,57,48,70,142,106,43,232,
26,32,126,194,252,239,175,98,191,94,
75,59,149,62,39,187,32,203,42,190,
19,243,13,133,45,61,204,187,168,247,
163,194,23,34,133,20,17,52,118,209,
146,193,13,40,255,52,227,32,255,13,
222,18,1,236,152,46,41,100,233,209,
91,141,148,115,175,25,135,193,77,254,
147,224,191,161,9,191,213,236,223,212,
250,190,231,251,170,127,41,212,227,19,
166,63,161,58,179,81,84,59,18,162,
57,166,130,248,71,139,184,28,120,151,
241,115,86,217,111,0,88,153,213,59,
172,123,123,78,182,46,159,10,105,178,
172,163,88,47,155,160,
}
local function decode_data(data)
local o = decode_key:crypt(data)
decode_key:reset()
return o
end
for i = 1, 10 do
print(decode_data("asdf"))
end

@ -1,41 +0,0 @@
#ifndef SKIPLIST_HH
#define SKIPLIST_HH
#include <stdint.h>
typedef struct skiplistNode
{
int64_t obj;
double score;
struct skiplistNode *backward;
struct skiplistLevel
{
struct skiplistNode *forward;
unsigned int span;
} level[];
} skiplistNode;
typedef struct skiplist
{
struct skiplistNode *header, *tail;
unsigned long length;
int level;
} skiplist;
typedef void (*slDeleteCb)(void *ud, int64_t obj);
void slFreeNode(skiplistNode *node);
skiplist *slCreate(void);
void slFree(skiplist *sl);
void slInsert(skiplist *sl, double score, int64_t obj);
int slDelete(skiplist *sl, double score, int64_t obj);
unsigned long slDeleteByRank(skiplist *sl, unsigned int start, unsigned int end, slDeleteCb cb, void *ud);
unsigned long slGetRank(skiplist *sl, double score, int64_t o);
skiplistNode *slGetNodeByRank(skiplist *sl, unsigned long rank);
skiplistNode *slFirstInRange(skiplist *sl, double min, double max);
skiplistNode *slLastInRange(skiplist *sl, double min, double max);
#endif //SKIPLIST_HH

@ -1,30 +0,0 @@
SKYNET_ROOT ?= ../../skynet
include $(SKYNET_ROOT)/platform.mk
PLAT ?= none
TARGET = ../../luaclib/skipset.so
ifeq ($(PLAT), macosx)
CFLAGS = -g -O2 -dynamiclib -Wl,-undefined,dynamic_lookup
else
ifeq ($(PLAT), linux)
CFLAGS = -g -O2 -shared -fPIC
endif
endif
LUA_LIB ?= $(SKYNET_ROOT)/3rd/lua/
LUA_INC ?= $(SKYNET_ROOT)/3rd/lua/
SKYNET_SRC ?= $(SKYNET_ROOT)/skynet-src
SRC = .
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(foreach dir, $(SRC), $(wildcard $(dir)/*.c))
$(CC) $(CFLAGS) $(SHARED) -I$(LUA_INC) -I$(SKYNET_SRC) $^ -o $@
clean:
rm -f *.o $(TARGET)

@ -1,394 +0,0 @@
#define LUA_LIB
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "lauxlib.h"
#include "lua.h"
// https://github.com/hongling0/lua-zset
#define SKIPLIST_MAXLEVEL 32
#define SKIPLIST_P 0.25
typedef struct skipsetNode
{
int64_t obj;
struct skipsetNode *backward;
struct skiplistLevel
{
struct skipsetNode *forward;
unsigned int span;
} level[];
} skipsetNode;
typedef struct skipset
{
struct skipsetNode *header, *tail;
unsigned long length;
int level;
} skipset;
static int slRandomLevel(void)
{
int level = 1;
while ((random() & 0xffff) < (SKIPLIST_P * 0xffff))
level += 1;
return (level < SKIPLIST_MAXLEVEL) ? level : SKIPLIST_MAXLEVEL;
}
static skipsetNode *slCreateNode(int level, int64_t obj)
{
skipsetNode *n = malloc(sizeof(*n) + level * sizeof(struct skiplistLevel));
n->obj = obj;
return n;
}
static int slInsert(skipset *sl, int64_t obj)
{
skipsetNode *update[SKIPLIST_MAXLEVEL], *x;
unsigned int rank[SKIPLIST_MAXLEVEL];
int i, level;
x = sl->header;
for (i = sl->level - 1; i >= 0; i--)
{
rank[i] = i == (sl->level - 1) ? 0 : rank[i + 1];
while (x->level[i].forward && x->level[i].forward->obj < obj)
{
rank[i] += x->level[i].span;
x = x->level[i].forward;
}
update[i] = x;
}
x = x->level[0].forward;
if (x && x->obj == obj)
return 0;
level = slRandomLevel();
if (level > sl->level)
{
for (i = sl->level; i < level; i++)
{
rank[i] = 0;
update[i] = sl->header;
update[i]->level[i].span = sl->length;
}
sl->level = level;
}
x = slCreateNode(level, obj);
for (i = 0; i < level; i++)
{
x->level[i].forward = update[i]->level[i].forward;
update[i]->level[i].forward = x;
x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
update[i]->level[i].span = (rank[0] - rank[i]) + 1;
}
for (i = level; i < sl->level; i++)
{
update[i]->level[i].span++;
}
x->backward = (update[0] == sl->header) ? NULL : update[0];
if (x->level[0].forward)
x->level[0].forward->backward = x;
else
sl->tail = x;
sl->length++;
return 1;
}
static void slDeleteNode(skipset *sl, skipsetNode *x, skipsetNode **update)
{
int i;
for (i = 0; i < sl->level; i++)
{
if (update[i]->level[i].forward == x)
{
update[i]->level[i].span += x->level[i].span - 1;
update[i]->level[i].forward = x->level[i].forward;
}
else
{
update[i]->level[i].span -= 1;
}
}
if (x->level[0].forward)
{
x->level[0].forward->backward = x->backward;
}
else
{
sl->tail = x->backward;
}
while (sl->level > 1 && sl->header->level[sl->level - 1].forward == NULL)
sl->level--;
sl->length--;
}
static void slFreeNode(skipsetNode *node)
{
free(node);
}
static int slDelete(skipset *sl, int64_t obj)
{
skipsetNode *update[SKIPLIST_MAXLEVEL], *x;
int i;
x = sl->header;
for (i = sl->level - 1; i >= 0; i--)
{
while (x->level[i].forward && x->level[i].forward->obj < obj)
x = x->level[i].forward;
update[i] = x;
}
x = x->level[0].forward;
if (x && (x->obj == obj))
{
slDeleteNode(sl, x, update);
slFreeNode(x);
return 1;
}
else
{
return 0; /* not found */
}
return 0; /* not found */
}
static unsigned long slGetRank(skipset *sl, int64_t obj)
{
skipsetNode *x;
unsigned long rank = 0;
int i;
x = sl->header;
for (i = sl->level - 1; i >= 0; i--)
{
while (x->level[i].forward && x->level[i].forward->obj <= obj)
{
rank += x->level[i].span;
x = x->level[i].forward;
}
if (x->obj && (x->obj == obj))
{
return rank;
}
}
return 0;
}
static skipsetNode *slGetNodeByRank(skipset *sl, unsigned long rank)
{
if (rank == 0 || rank > sl->length)
return NULL;
skipsetNode *x;
unsigned long traversed = 0;
int i;
x = sl->header;
for (i = sl->level - 1; i >= 0; i--)
{
while (x->level[i].forward && (traversed + x->level[i].span) <= rank)
{
traversed += x->level[i].span;
x = x->level[i].forward;
}
if (traversed == rank)
{
return x;
}
}
return NULL;
}
unsigned long slDeleteByRank(skipset *sl, unsigned int rank)
{
skipsetNode *update[SKIPLIST_MAXLEVEL], *x;
unsigned long traversed = 0;
int i;
x = sl->header;
for (i = sl->level - 1; i >= 0; i--)
{
while (x->level[i].forward && (traversed + x->level[i].span) < rank)
{
traversed += x->level[i].span;
x = x->level[i].forward;
}
update[i] = x;
}
x = x->level[0].forward;
if (x)
{
slDeleteNode(sl, x, update);
slFreeNode(x);
return 1;
}
return 0;
}
static skipset *slCreate(void)
{
int j;
skipset *sl;
sl = malloc(sizeof(*sl));
sl->level = 1;
sl->length = 0;
sl->header = slCreateNode(SKIPLIST_MAXLEVEL, 0);
for (j = 0; j < SKIPLIST_MAXLEVEL; j++)
{
sl->header->level[j].forward = NULL;
sl->header->level[j].span = 0;
}
sl->header->backward = NULL;
sl->tail = NULL;
return sl;
}
static void slFree(skipset *sl)
{
skipsetNode *node = sl->header->level[0].forward, *next;
free(sl->header);
while (node)
{
next = node->level[0].forward;
slFreeNode(node);
node = next;
}
free(sl);
}
static inline skipset *
_to_skipset(lua_State *L, int idx)
{
skipset **sl = lua_touserdata(L, idx);
if (sl == NULL)
{
luaL_error(L, "must be skipset object");
}
return *sl;
}
static int
_insert(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
lua_Integer obj = luaL_checkinteger(L, 2);
lua_pushboolean(L, slInsert(sl, obj));
return 1;
}
static int
_delete(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
lua_Integer obj = luaL_checkinteger(L, 2);
lua_pushboolean(L, slDelete(sl, obj));
return 1;
}
static int
_get_count(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
lua_pushinteger(L, sl->length);
return 1;
}
static int
_get_rank(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
lua_Integer obj = luaL_checkinteger(L, 2);
unsigned long rank = slGetRank(sl, obj);
if (rank == 0)
{
return 0;
}
lua_pushinteger(L, rank);
return 1;
}
static int
_get_by_rank(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
unsigned long r1 = luaL_checkinteger(L, 2);
skipsetNode *node = slGetNodeByRank(sl, r1);
if (node)
{
lua_pushinteger(L, node->obj);
return 1;
}
return 0;
}
static int
_delete_by_rank(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
unsigned int rank = luaL_checkinteger(L, 2);
lua_pushinteger(L, slDeleteByRank(sl, rank));
return 1;
}
static int
_new(lua_State *L)
{
skipset *psl = slCreate();
skipset **sl = (skipset **)lua_newuserdata(L, sizeof(skipset *));
*sl = psl;
lua_pushvalue(L, lua_upvalueindex(1));
lua_setmetatable(L, -2);
return 1;
}
static int
_release(lua_State *L)
{
skipset *sl = _to_skipset(L, 1);
slFree(sl);
return 0;
}
LUAMOD_API int
luaopen_skipset_c(lua_State *L)
{
luaL_checkversion(L);
luaL_Reg l[] = {
{"insert", _insert},
{"delete", _delete},
{"delete_byrank", _delete_by_rank},
{"count", _get_count},
{"rank", _get_rank},
{"byrank", _get_by_rank},
{NULL, NULL}};
lua_createtable(L, 0, 2);
luaL_newlib(L, l);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _release);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, _get_count);
lua_setfield(L, -2, "__len");
lua_pushcclosure(L, _new, 1);
return 1;
}

@ -1,29 +0,0 @@
SKYNET_ROOT ?= ../../skynet
include $(SKYNET_ROOT)/platform.mk
PLAT ?= none
TARGET = ../../luaclib/lsyslog.so
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
LUA_LIB ?= $(SKYNET_ROOT)/3rd/lua/
LUA_INC ?= $(SKYNET_ROOT)/3rd/lua/
SRC = .
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(foreach dir, $(SRC), $(wildcard $(dir)/*.c))
$(CC) $(CFLAGS) $(SHARED) -I$(LUA_INC) $^ -o $@
clean:
rm -f *.o $(TARGET)

@ -1,102 +0,0 @@
// #include <config.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
static int
lsyslog_open(lua_State *L)
{
static char *persistent_ident = NULL;
const char *ident = luaL_checkstring(L, 1);
int facility = luaL_checkinteger(L, 2);
if (persistent_ident != NULL) {
free(persistent_ident);
}
persistent_ident = strdup(ident);
openlog(persistent_ident, LOG_PID, facility);
return 0;
}
static int
lsyslog_log(lua_State *L)
{
int level = luaL_checkinteger(L, 1);
const char *line = luaL_checkstring(L, 2);
syslog(level, "%s", line);
return 0;
}
static int
lsyslog_close(lua_State *L)
{
closelog();
return 0;
}
#define set_field(f,v) lua_pushliteral(L, v); \
lua_setfield(L, -2, f)
#define add_constant(c) lua_pushinteger(L, LOG_##c); \
lua_setfield(L, -2, #c)
int
luaopen_lsyslog(lua_State *L)
{
const luaL_Reg API[] = {
{ "open", lsyslog_open },
{ "close", lsyslog_close },
{ "log", lsyslog_log },
{ NULL, NULL }
};
luaL_newlib(L, API);
// set_field("_COPYRIGHT", "Copyright (C) 2014 " PACKAGE_AUTHOR);
// set_field("_DESCRIPTION", PACKAGE_DESCRIPTION);
// set_field("_VERSION", PACKAGE_VERSION);
lua_newtable(L);
add_constant(AUTH);
add_constant(AUTHPRIV);
add_constant(CRON);
add_constant(DAEMON);
add_constant(FTP);
add_constant(KERN);
add_constant(LOCAL0);
add_constant(LOCAL1);
add_constant(LOCAL2);
add_constant(LOCAL3);
add_constant(LOCAL4);
add_constant(LOCAL5);
add_constant(LOCAL6);
add_constant(LOCAL7);
add_constant(LPR);
add_constant(MAIL);
add_constant(NEWS);
add_constant(SYSLOG);
add_constant(USER);
add_constant(UUCP);
lua_setfield(L, -2, "FACILITY");
lua_newtable(L);
add_constant(EMERG);
add_constant(ALERT);
add_constant(CRIT);
add_constant(ERR);
add_constant(WARNING);
add_constant(NOTICE);
add_constant(INFO);
add_constant(DEBUG);
lua_setfield(L, -2, "LEVEL");
return 1;
}

@ -1,88 +0,0 @@
# simple Makefile for termfx. Works for Linux, MacOS X, probably other unixen
#
# Gunnar Zötl <gz@tset.de>, 2014-2015.
# Released under the terms of the MIT license. See file LICENSE for details.
TERMBOX ?= ../../3rd/termbox
SKYNET_ROOT?= ../../skynet
# try some automatic discovery. If that does not work for you, just set
# the following values manually.
OS = $(shell uname -s)
LUAVERSION = $(shell lua -e "print(string.match(_VERSION, '%d+%.%d+'))")
# LUA_BINDIR = $(shell dirname `which lua`)
# LUAROOT = $(shell dirname $(LUA_BINDIR))
OBJS = termfx.o termfx_color.o tbutils.o
TARGET = termfx.so
CC = gcc
CFLAGS = -fPIC -Wall
LUA_INCDIR ?= $(SKYNET_ROOT)/3rd/lua/
LUA_LIBDIR ?= $(SKYNET_ROOT)/3rd/lua/
# OS specialities
ifeq ($(OS),Darwin)
LIBFLAG = -bundle -undefined dynamic_lookup -all_load
else
LIBFLAG = -shared
endif
ifdef DEBUG
CCFLAGS=-g $(CFLAGS)
CLDFLAGS=-g -lefence $(LIBFLAG)
else
CCFLAGS=$(CFLAGS)
CLDFLAGS=$(LIBFLAG)
endif
# install target locations
INST_DIR = /usr/local
INST_LIBDIR = $(INST_DIR)/lib/lua/$(LUAVERSION)
INST_LUADIR = $(INST_DIR)/share/lua/$(LUAVERSION)
all: $(TARGET)
$(TARGET): $(OBJS) libtermbox.a
$(CC) $(CLDFLAGS) -o $@ -L$(LUA_LIBDIR) $(OBJS) -L. -ltermbox
%.o: %.c termbox.h termfx.h
$(CC) $(CCFLAGS) -I$(LUA_INCDIR) -c $< -o $@
# $(TERMBOX):
# git clone https://github.com/nullgemm/termbox_next.git
termbox.h: $(TERMBOX)/src/termbox.h
cp $(TERMBOX)/src/$@ .
libtermbox.a: $(TERMBOX)/bin/termbox.a
cp $< $@
$(TERMBOX)/bin/termbox.a: $(TERMBOX)
cd $(TERMBOX) && FLAGS="-fPIC" make
$(TERMBOX)/src/termbox.h: $(TERMBOX)
touch $@
install:
mkdir -p $(INST_LIBDIR)
cp $(TARGET) $(INST_LIBDIR)
clean:
find . -name "*~" -exec rm {} \;
find . -name .DS_Store -exec rm {} \;
find . -name "._*" -exec rm {} \;
rm -f *.a *.o *.so core termbox.h
rm -f screenshot.html samples/screenshot.html
cd $(TERMBOX) && make clean
distclean: clean
rm -rf $(TERMBOX)
check:
cppcheck *.c
dist: $(TERMBOX) clean
cd $(TERMBOX) && rm -rf .git .gitignore

@ -1,272 +0,0 @@
/* mini_utf8.h
*
* Gunnar Zötl <gz@tset.de> 2014
*
* a tiny library to deal with utf8 encoded strings. Tries to fault
* invalid unicode codepoints and invalid utf8 sequences.
*
* Stuff starting with _mini_utf8_* is reserved and private. Don't name your
* identifiers like that, and don't use stuff named like that.
*
* Needed #includes:
* -----------------
* -
*
* Functions:
* ----------
*
* int mini_utf8_check_encoding(const char* str)
* test all characters in a string for valid utf8 encoding. Returns
* 0 if the string is valid utf8, 1 if it is pure ASCII, or -1, if
* the string is not valid utf8. We do a somewhat relaxed test in
* that all chars in the range [0x01-0x1F] are considered valid.
*
* int mini_utf8_decode(const char **str)
* returns the next valid utf8 character from *str, updating *str
* to point behind that char. If *str points to a 0 byte, 0 is
* returned and *str is not updated. If *str does not point to a
* valid utf8 encoded char, -1 is returned and *str is not updated.
*
* int mini_utf8_encode(int cp, const char* str, int len)
* encodes the codepoint cp into an utf8 byte sequence and stores
* that into str, where len bytes are available. If that went without
* errors, the length of the encoded sequence is returned. If cp is
* not a valid code point, -1 is returned, for all other problems,
* 0 is returned. If cp is 0, it is stored as a single byte 0, even
* if that is not really valid utf8. Also, all chars in the range
* [0x01-0x1F] are considered valid.
*
* int mini_utf8_strlen(const char *str)
* returns the number of utf8 codepoints in the string str, or -1 if
* the string contains invalid utf8 sequences.
*
* int mini_utf8_byteoffset(const char *str, int cpno)
* returns the number of bytes from the start of the string to the
* start of codepoint number cpno. Returns >=0 for the offset, or
* -1 if the string had less than cpno codepoints, or contained an
* invalid utf8 sequence.
*
* Example:
* --------
*
#include <stdio.h>
#include <stdlib.h>
#include "mini_utf8.h"
int main(int argc, char **argv)
{
int size = 0x11FFFF;
int l = size * 4 + 1, i = 0, ok = 1, cp = 0;
int *ibuf = calloc(size, sizeof(int));
char *cbuf = calloc(l, sizeof(char));
char *str = cbuf;
while (cp < size) {
cp = cp + 1;
int n = mini_utf8_encode(cp, str, l);
if (n > 0) {
l -= n;
str += n;
ibuf[i++] = cp;
}
}
*str = 0;
size = i;
str = cbuf;
for (i = 0; ok && (i < size); ++i) {
cp = mini_utf8_decode((const char**)&str);
ok = (cp == ibuf[i]);
}
ok = ok && (mini_utf8_strlen(cbuf) == size);
printf("Roundtrip test %s.\n", ok ? "succeeded" : "failed");
ok = mini_utf8_check_encoding(cbuf);
printf("utf8 check %s.\n", ok >= 0 ? "succeeded" : "failed");
return ok < 0;
}
*
* License:
* --------
*
* Copyright (c) 2014 Gunnar Zötl <gz@tset.de>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _mini_utf8
#define _mini_utf8
#define _mini_utf8_in_range(c, s, e) ((s) <= (c) && (c) <= (e))
/* The patterns for the encoding check are taken from
* http://www.w3.org/International/questions/qa-forms-utf-8
*/
static inline int mini_utf8_check_encoding(const char *str)
{
const unsigned char *s = (const unsigned char*) str;
int isu = 1;
int isa = 1;
while (*s && isu) {
if (*s <= 0x7F) {
s += 1;
continue; /* [\x09\x0A\x0D\x20-\x7E] # ASCII (somewhat relaxed) */
}
isa = 0; /* if we get here, the file is not pure ASCII */
if (_mini_utf8_in_range(*s, 0xC2, 0xDF) && _mini_utf8_in_range(s[1], 0x80, 0xBF)) {
s += 2; /* [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte */
} else if (*s == 0xE0 && _mini_utf8_in_range(s[1], 0xA0, 0xBF) && _mini_utf8_in_range(s[2], 0x80, 0xBF)) {
s += 3; /* \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs */
} else if ((*s <= 0xEC || *s == 0xEE || *s == 0xEF) && _mini_utf8_in_range(s[1], 0x80, 0xBF) && _mini_utf8_in_range(s[2], 0x80, 0xBF)) {
s += 3; /* [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte */
} else if (*s == 0xED && _mini_utf8_in_range(s[1], 0x80, 0x9F) && _mini_utf8_in_range(s[2], 0x80, 0xBF)) {
s += 3; /* \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates */
} else if (*s == 0xF0 && _mini_utf8_in_range(s[1], 0x90, 0xBF) && _mini_utf8_in_range(s[2], 0x80, 0xBF) && _mini_utf8_in_range(s[3], 0x80, 0xBF)) {
s += 4; /* \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 */
} else if (*s <= 0xF3 && _mini_utf8_in_range(s[1], 0x80, 0xBF) && _mini_utf8_in_range(s[2], 0x80, 0xBF) && _mini_utf8_in_range(s[3], 0x80, 0xBF)) {
s += 4; /* [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 */
} else if (*s == 0xF4 && _mini_utf8_in_range(s[1], 0x80, 0x8F) && _mini_utf8_in_range(s[2], 0x80, 0xBF) && _mini_utf8_in_range(s[3], 0x80, 0xBF)) {
s += 4; /* \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 */
} else
isu = 0;
}
if (isa && isu)
return 1;
else if (isu)
return 0;
return -1;
}
/* bits start end bytes encoding
* 7 U+0000 U+007F 1 0xxxxxxx
* 11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
* 16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
* 21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*
* validity checking derived from above patterns
*/
static inline int mini_utf8_decode(const char **str)
{
const unsigned char *s = (const unsigned char*) *str;
int ret = -1;
if (!*s) return 0;
if (*s <= 0x7F) {
ret = s[0]; /* ASCII */
*str = (char*) s+1;
return ret;
} else if (*s < 0xC2) {
return -1;
} else if (*s<= 0xDF) {
if ((s[1] & 0xC0) != 0x80) return -1;
ret = ((s[0] & 0x1F) << 6) | (s[1] & 0x3F);
*str = (char*) s+2;
return ret;
} else if (*s <= 0xEF) {
if ((s[1] & 0xC0) != 0x80) return -1;
if (*s == 0xE0 && s[1] < 0xA0) return -1;
if (*s == 0xED && s[1] > 0x9F) return -1;
if ((s[2] & 0xC0) != 0x80) return -1;
ret = ((s[0] & 0x0F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
*str = (char*) s+3;
return ret;
} else if (*s <= 0xF4) {
if ((s[1] & 0xC0) != 0x80) return -1;
if (*s == 0xF0 && s[1] < 0x90) return -1;
if (*s == 0xF4 && s[1] > 0x8F) return -1;
if ((s[2] & 0xC0) != 0x80) return -1;
if ((s[3] & 0xC0) != 0x80) return -1;
ret = ((s[0] & 0x0F) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F);
*str = (char*) s+4;
return ret;
}
return ret;
}
/* only utf16 surrogate pairs (0xD800-0xDFFF) are invalid unicode
* codepoints
*/
static inline int mini_utf8_encode(int cp, char *str, int len)
{
unsigned char *s = (unsigned char*) str;
if (cp <= 0x7F) {
if (len < 1) return 0;
*s = (cp & 0x7F);
return 1;
} else if (cp <= 0x7FF) {
if (len < 2) return 0;
*s++ = (cp >> 6) | 0xC0;
*s = (cp & 0x3F) | 0x80;
return 2;
} else if (cp <= 0xFFFF) {
if (0xD800 <= cp && cp <= 0xDFFF) return -1;
if (len < 3) return 0;
*s++ = (cp >> 12) | 0xE0;
*s++ = ((cp >> 6) & 0x3F) | 0x80;
*s = (cp & 0x3F) | 0x80;
return 3;
} else if (cp <= 0x10FFFF) {
if (len < 4) return 0;
*s++ =(cp >> 18) | 0xF0;
*s++ =((cp >> 12) & 0x3F) | 0x80;
*s++ =((cp >> 6) & 0x3F) | 0x80;
*s =(cp & 0x3F) | 0x80;
return 4;
}
return -1;
}
static inline int mini_utf8_strlen(const char *str)
{
const char *s = str;
int len = 0;
int ok = mini_utf8_decode(&s);
while (ok > 0) {
++len;
ok = mini_utf8_decode(&s);
}
if (ok == 0)
return len;
return -1;
}
static inline int mini_utf8_byteoffset(const char *str, int cpno)
{
const char *s = str;
int cnt = 0;
int ok = 1;
for (cnt = 0; (cnt < cpno) && (ok > 0); ++cnt) {
ok = mini_utf8_decode(&s);
}
if (ok > 0)
return (int)(s - str);
return -1;
}
#endif /* _mini_utf8 */

@ -1,218 +0,0 @@
/* termbox utils
*
* Utility functions for use with termbox
*
* Gunnar Zötl <gz@tset.de>, 2015
* Released under the terms of the MIT license. See file LICENSE for details.
*/
#include <string.h>
#include <stdlib.h>
#include "termbox.h"
#include "tbutils.h"
void tbu_blitbuffer(struct tb_cell *to, int tw, int th, int x, int y, const struct tb_cell *from, int w, int h)
{
if (x + w < 0 || x >= tw || w <= 0)
return;
if (y + h < 0 || y >= th || h <= 0)
return;
int xo = 0, yo = 0, ww = w, hh = h;
if (x < 0) {
xo = -x;
ww -= xo;
x = 0;
}
if (y < 0) {
yo = -y;
hh -= yo;
y = 0;
}
if (ww > tw - x) {
ww = tw - x;
}
if (hh > th - y) {
hh = th - y;
}
int sy;
struct tb_cell *dst = &CELL(to, tw, x, y);
const struct tb_cell *src = from + yo * w + xo;
size_t size = sizeof(struct tb_cell) * ww;
for (sy = 0; sy < hh; ++sy) {
memcpy(dst, src, size);
dst += tw;
src += w;
}
}
void tbu_blit(int x, int y, const struct tb_cell *from, int w, int h)
{
int bbw = tb_width();
int bbh = tb_height();
struct tb_cell *bb = tb_cell_buffer();
tbu_blitbuffer(bb, bbw, bbh, x, y, from, w, h);
}
void tbu_fillbufferregion(struct tb_cell *buf, int bw, int bh, int x, int y, int w, int h, const struct tb_cell *fill)
{
if (x + w < 0 || x >= bw || w <= 0)
return;
if (y + h < 0 || y >= bh || h <= 0)
return;
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
if (x + w > bw) {
w = bw - x;
}
if (y + h > bh) {
h = bh - y;
}
int sx, sy;
struct tb_cell *dst = &CELL(buf, bw, x, y);
for (sy = 0; sy < h; ++sy) {
for (sx = 0; sx < w; ++sx) {
dst[sx] = *fill;
}
dst += bw;
}
}
void tbu_fillregion(int x, int y, int w, int h, const struct tb_cell *fill)
{
int bbw = tb_width();
int bbh = tb_height();
struct tb_cell *bb = tb_cell_buffer();
tbu_fillbufferregion(bb, bbw, bbh, x, y, w, h, fill);
}
void tbu_copybufferregion(struct tb_cell *buf, int bw, int bh, int tx, int ty, int x, int y, int w, int h)
{
if (w < 1 || h < 1)
return;
if (x >= bw || x + w < 0 || y >= bh || y + h < 0)
return;
if (tx >= bw || tx + w < 0 || ty >= bh || ty + h < 0)
return;
if (x < 0) {
int dx = -x;
x = 0;
tx += dx;
w -= dx;
}
if (x + w > bw) {
w = bw - x;
}
if (tx < 0) {
int dx = -tx;
tx = 0;
x += dx;
w -= dx;
}
if (tx + w > bw) {
w = bw - tx;
}
if (y < 0) {
int dy = -y;
y = 0;
ty += dy;
h -= dy;
}
if (y + h > bh) {
h = bh - y;
}
if (ty < 0) {
int dy = -ty;
ty = 0;
y += dy;
h -= dy;
}
if (ty + h > bh) {
h = bh - ty;
}
int ys = 1;
if (ty > y) {
y = y + h - 1;
ty = ty + h - 1;
ys = -1;
}
int ry;
int from = x, to = tx;
if (y > 0) {
from += y * bw;
}
if (ty > 0) {
to += ty * bw;
}
for (ry = 0; ry < h; ++ry) {
int cfy = from + (ry * ys * bw);
int cty = to + (ry * ys * bw);
memmove(&buf[cty], &buf[cfy], w * sizeof(struct tb_cell));
}
}
void tbu_copyregion(int tx, int ty, int x, int y, int w, int h)
{
int bbw = tb_width();
int bbh = tb_height();
struct tb_cell *bb = tb_cell_buffer();
tbu_copybufferregion(bb, bbw, bbh, tx, ty, x, y, w, h);
}
void tbu_scrollbufferregion(struct tb_cell *buf, int bw, int bh, int x, int y, int w, int h, int sx, int sy, const struct tb_cell *fill)
{
int fx = x, tx = x;
int fy = y, ty = y;
if (sx < 0) {
sx = -1;
fx = x + 1;
} else if (sx > 0) {
sx = 1;
tx = x + 1;
}
if (sy < 0) {
sy = -1;
fy = y + 1;
} else if (sy > 0) {
sy = 1;
ty = y + 1;
}
tbu_copybufferregion(buf, bw, bh, tx, ty, fx, fy, w - abs(sx), h - abs(sy));
if (sx != 0) {
int fillx = sx > 0 ? x : x + w - 1;
tbu_fillbufferregion(buf, bw, bh, fillx, y, 1, h, fill);
}
if (sy != 0) {
int filly = sy > 0 ? y : y + h - 1;
tbu_fillbufferregion(buf, bw, bh, x, filly, w, 1, fill);
}
}
void tbu_scrollregion(int x, int y, int w, int h, int sx, int sy, const struct tb_cell *fill)
{
int bbw = tb_width();
int bbh = tb_height();
struct tb_cell *bb = tb_cell_buffer();
tbu_scrollbufferregion(bb, bbw, bbh, x, y, w, h, sx, sy, fill);
}

@ -1,102 +0,0 @@
/* termbox utils
*
* Utility functions for use with termbox
*
* Gunnar Zötl <gz@tset.de>, 2015
* Released under the terms of the MIT license. See file LICENSE for details.
*/
#ifndef tbutils_h
#define tbutils_h
#define CELL(buf, w, x, y) (buf)[(y) * (w) + (x)]
/* blit one buffer into another buffer
*
* Arguments:
* to target buffer to blit into
* tw, th target buffer dimensions
* x, y target coordinates
* from source buffer, must be different from "to"
* w, h dimensions of source buffer
*/
void tbu_blitbuffer(struct tb_cell *to, int tw, int th, int x, int y, const struct tb_cell *from, int w, int h);
/* blit buffer into terminal back buffer
*
* Arguments:
* x, y target coordinates
* from source buffer
* w, h dimensions of source buffer
*/
void tbu_blit(int x, int y, const struct tb_cell *from, int w, int h);
/* fill a region of a buffer
*
* Arguments:
* buf target buffer
* bw, bh target buffer dimensions
* x, y target coordinates
* w, h dimensions of rect to fill
* fill cell describing what to fill with
*/
void tbu_fillbufferregion(struct tb_cell *buf, int bw, int bh, int x, int y, int w, int h, const struct tb_cell *fill);
/* fill a region of the terminal back buffer
*
* Arguments:
* x, y target coordinates
* w, h dimensions of rect to fill
* fill cell describing what to fill with
*/
void tbu_fillregion(int x, int y, int w, int h, const struct tb_cell *fill);
/* copy a region of a buffer to another place
*
* Arguments:
* buf target buffer
* bw, bh target buffer dimensions
* tx, ty target coordinates
* x, y source coordinates
* w, h dimensions of rect to copy
*/
void tbu_copybufferregion(struct tb_cell *buf, int bw, int bh, int tx, int ty, int x, int y, int w, int h);
/* copy a region of the terminal back buffer to another place
*
* Arguments:
* tx, ty target coordinates
* x, y source coordinates
* w, h dimensions of rect to copy
*/
void tbu_copyregion(int tx, int ty, int x, int y, int w, int h);
/* scroll a region within a buffer
*
* Arguments:
* buf target buffer
* bw, bh target buffer dimensions
* x, y coordinates of scrolled region
* w, h dimensions of scrolled region
* sx, sy directions to scroll in x and y
* fill what to fill the cleared space with
*
* Note: the amount by which is scrolled is always 1.
* sy and sx only give the directions: -1 left/up, 0 none, 1 right/down.
*/
void tbu_scrollbufferregion(struct tb_cell *buf, int bw, int bh, int x, int y, int w, int h, int sx, int sy, const struct tb_cell *fill);
/* scroll a region within the terminal back buffer
*
* Arguments:
* x, y coordinates of scrolled region
* w, h dimensions of scrolled region
* sx, sy directions to scroll in x and y
* fill what to fill the cleared space with
*
* Note: the amount by which is scrolled is always 1.
* sy and sx only give the directions: -1 left/up, 0 none, 1 right/down.
*/
void tbu_scrollregion(int x, int y, int w, int h, int sx, int sy, const struct tb_cell *fill);
#endif /* tbutils_h */

@ -1,307 +0,0 @@
#ifndef H_TERMBOX
#define H_TERMBOX
#include <stdint.h>
// shared objects
#if __GNUC__ >= 4
#define SO_IMPORT __attribute__((visibility("default")))
#else
#define SO_IMPORT
#endif
// c++
#ifdef __cplusplus
extern "C" {
#endif
// Key constants. See also struct tb_event's key field.
// These are a safe subset of terminfo keys, which exist on all popular
// terminals. Termbox uses only them to stay truly portable.
#define TB_KEY_F1 (0xFFFF-0)
#define TB_KEY_F2 (0xFFFF-1)
#define TB_KEY_F3 (0xFFFF-2)
#define TB_KEY_F4 (0xFFFF-3)
#define TB_KEY_F5 (0xFFFF-4)
#define TB_KEY_F6 (0xFFFF-5)
#define TB_KEY_F7 (0xFFFF-6)
#define TB_KEY_F8 (0xFFFF-7)
#define TB_KEY_F9 (0xFFFF-8)
#define TB_KEY_F10 (0xFFFF-9)
#define TB_KEY_F11 (0xFFFF-10)
#define TB_KEY_F12 (0xFFFF-11)
#define TB_KEY_INSERT (0xFFFF-12)
#define TB_KEY_DELETE (0xFFFF-13)
#define TB_KEY_HOME (0xFFFF-14)
#define TB_KEY_END (0xFFFF-15)
#define TB_KEY_PGUP (0xFFFF-16)
#define TB_KEY_PGDN (0xFFFF-17)
#define TB_KEY_ARROW_UP (0xFFFF-18)
#define TB_KEY_ARROW_DOWN (0xFFFF-19)
#define TB_KEY_ARROW_LEFT (0xFFFF-20)
#define TB_KEY_ARROW_RIGHT (0xFFFF-21)
#define TB_KEY_MOUSE_LEFT (0xFFFF-22)
#define TB_KEY_MOUSE_RIGHT (0xFFFF-23)
#define TB_KEY_MOUSE_MIDDLE (0xFFFF-24)
#define TB_KEY_MOUSE_RELEASE (0xFFFF-25)
#define TB_KEY_MOUSE_WHEEL_UP (0xFFFF-26)
#define TB_KEY_MOUSE_WHEEL_DOWN (0xFFFF-27)
// These are all ASCII code points below SPACE character and a BACKSPACE key.
#define TB_KEY_CTRL_TILDE 0x00
#define TB_KEY_CTRL_2 0x00 // clash with 'CTRL_TILDE'
#define TB_KEY_CTRL_A 0x01
#define TB_KEY_CTRL_B 0x02
#define TB_KEY_CTRL_C 0x03
#define TB_KEY_CTRL_D 0x04
#define TB_KEY_CTRL_E 0x05
#define TB_KEY_CTRL_F 0x06
#define TB_KEY_CTRL_G 0x07
#define TB_KEY_BACKSPACE 0x08
#define TB_KEY_CTRL_H 0x08 // clash with 'CTRL_BACKSPACE'
#define TB_KEY_TAB 0x09
#define TB_KEY_CTRL_I 0x09 // clash with 'TAB'
#define TB_KEY_CTRL_J 0x0A
#define TB_KEY_CTRL_K 0x0B
#define TB_KEY_CTRL_L 0x0C
#define TB_KEY_ENTER 0x0D
#define TB_KEY_CTRL_M 0x0D // clash with 'ENTER'
#define TB_KEY_CTRL_N 0x0E
#define TB_KEY_CTRL_O 0x0F
#define TB_KEY_CTRL_P 0x10
#define TB_KEY_CTRL_Q 0x11
#define TB_KEY_CTRL_R 0x12
#define TB_KEY_CTRL_S 0x13
#define TB_KEY_CTRL_T 0x14
#define TB_KEY_CTRL_U 0x15
#define TB_KEY_CTRL_V 0x16
#define TB_KEY_CTRL_W 0x17
#define TB_KEY_CTRL_X 0x18
#define TB_KEY_CTRL_Y 0x19
#define TB_KEY_CTRL_Z 0x1A
#define TB_KEY_ESC 0x1B
#define TB_KEY_CTRL_LSQ_BRACKET 0x1B // clash with 'ESC'
#define TB_KEY_CTRL_3 0x1B // clash with 'ESC'
#define TB_KEY_CTRL_4 0x1C
#define TB_KEY_CTRL_BACKSLASH 0x1C // clash with 'CTRL_4'
#define TB_KEY_CTRL_5 0x1D
#define TB_KEY_CTRL_RSQ_BRACKET 0x1D // clash with 'CTRL_5'
#define TB_KEY_CTRL_6 0x1E
#define TB_KEY_CTRL_7 0x1F
#define TB_KEY_CTRL_SLASH 0x1F // clash with 'CTRL_7'
#define TB_KEY_CTRL_UNDERSCORE 0x1F // clash with 'CTRL_7'
#define TB_KEY_SPACE 0x20
#define TB_KEY_BACKSPACE2 0x7F
#define TB_KEY_CTRL_8 0x7F // clash with 'BACKSPACE2'
// These are non-existing ones.
// #define TB_KEY_CTRL_1 clash with '1'
// #define TB_KEY_CTRL_9 clash with '9'
// #define TB_KEY_CTRL_0 clash with '0'
// Alt modifier constant, see tb_event.mod field and tb_select_input_mode function.
// Mouse-motion modifier
#define TB_MOD_ALT 0x01
#define TB_MOD_MOTION 0x02
// Colors (see struct tb_cell's fg and bg fields).
#define TB_DEFAULT 0x00
#define TB_BLACK 0x01
#define TB_RED 0x02
#define TB_GREEN 0x03
#define TB_YELLOW 0x04
#define TB_BLUE 0x05
#define TB_MAGENTA 0x06
#define TB_CYAN 0x07
#define TB_WHITE 0x08
// Attributes, it is possible to use multiple attributes by combining them
// using bitwise OR ('|'). Although, colors cannot be combined. But you can
// combine attributes and a single color. See also struct tb_cell's fg and bg
// fields.
#define TB_BOLD 0x01000000
#define TB_UNDERLINE 0x02000000
#define TB_REVERSE 0x04000000
// A cell, single conceptual entity on the terminal screen. The terminal screen
// is basically a 2d array of cells. It has the following fields:
// - 'ch' is a unicode character
// - 'fg' foreground color and attributes
// - 'bg' background color and attributes
struct tb_cell
{
uint32_t ch;
uint32_t fg;
uint32_t bg;
};
#define TB_EVENT_KEY 1
#define TB_EVENT_RESIZE 2
#define TB_EVENT_MOUSE 3
// An event, single interaction from the user. The 'mod' and 'ch' fields are
// valid if 'type' is TB_EVENT_KEY. The 'w' and 'h' fields are valid if 'type'
// is TB_EVENT_RESIZE. The 'x' and 'y' fields are valid if 'type' is
// TB_EVENT_MOUSE. The 'key' field is valid if 'type' is either TB_EVENT_KEY
// or TB_EVENT_MOUSE. The fields 'key' and 'ch' are mutually exclusive; only
// one of them can be non-zero at a time.
struct tb_event
{
uint8_t type;
uint8_t mod; // modifiers to either 'key' or 'ch' below
uint16_t key; // one of the TB_KEY_* constants
uint32_t ch; // unicode character
int32_t w;
int32_t h;
int32_t x;
int32_t y;
};
// Error codes returned by tb_init(). All of them are self-explanatory, except
// the pipe trap error. Termbox uses unix pipes in order to deliver a message
// from a signal handler (SIGWINCH) to the main event reading loop. Honestly in
// most cases you should just check the returned code as < 0.
#define TB_EUNSUPPORTED_TERMINAL -1
#define TB_EFAILED_TO_OPEN_TTY -2
#define TB_EPIPE_TRAP_ERROR -3
// Initializes the termbox library. This function should be called before any
// other functions. Function tb_init is same as tb_init_file("/dev/tty"). After successful initialization, the library must be
// finalized using the tb_shutdown() function.
SO_IMPORT int tb_init(void);
SO_IMPORT int tb_init_file(const char* name);
SO_IMPORT void tb_shutdown(void);
// Returns the size of the internal back buffer (which is the same as
// terminal's window size in characters). The internal buffer can be resized
// after tb_clear() or tb_present() function calls. Both dimensions have an
// unspecified negative value when called before tb_init() or after
// tb_shutdown().
SO_IMPORT int tb_width(void);
SO_IMPORT int tb_height(void);
// Clears the internal back buffer using TB_DEFAULT color or the
// color/attributes set by tb_set_clear_attributes() function.
SO_IMPORT void tb_clear(void);
SO_IMPORT void tb_set_clear_attributes(uint32_t fg, uint32_t bg);
// Synchronizes the internal back buffer with the terminal.
SO_IMPORT void tb_present(void);
#define TB_HIDE_CURSOR -1
// Sets the position of the cursor. Upper-left character is (0, 0). If you pass
// TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor
// is hidden by default.
SO_IMPORT void tb_set_cursor(int cx, int cy);
// Changes cell's parameters in the internal back buffer at the specified
// position.
SO_IMPORT void tb_put_cell(int x, int y, const struct tb_cell* cell);
SO_IMPORT void tb_change_cell(int x, int y, uint32_t ch, uint32_t fg,
uint32_t bg);
// Copies the buffer from 'cells' at the specified position, assuming the
// buffer is a two-dimensional array of size ('w' x 'h'), represented as a
// one-dimensional buffer containing lines of cells starting from the top.
// (DEPRECATED: use tb_cell_buffer() instead and copy memory on your own)
SO_IMPORT void tb_blit(int x, int y, int w, int h, const struct tb_cell* cells);
// Returns a pointer to internal cell back buffer. You can get its dimensions
// using tb_width() and tb_height() functions. The pointer stays valid as long
// as no tb_clear() and tb_present() calls are made. The buffer is
// one-dimensional buffer containing lines of cells starting from the top.
SO_IMPORT struct tb_cell* tb_cell_buffer(void);
#define TB_INPUT_CURRENT 0 // 000
#define TB_INPUT_ESC 1 // 001
#define TB_INPUT_ALT 2 // 010
#define TB_INPUT_MOUSE 4 // 100
// Sets the termbox input mode. Termbox has two input modes:
// 1. Esc input mode.
// When ESC sequence is in the buffer and it doesn't match any known
// ESC sequence => ESC means TB_KEY_ESC.
// 2. Alt input mode.
// When ESC sequence is in the buffer and it doesn't match any known
// sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
//
// You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the
// modes (e.g. TB_INPUT_ESC | TB_INPUT_MOUSE). If none of the main two modes
// were set, but the mouse mode was, TB_INPUT_ESC mode is used. If for some
// reason you've decided to use (TB_INPUT_ESC | TB_INPUT_ALT) combination, it
// will behave as if only TB_INPUT_ESC was selected.
//
// If 'mode' is TB_INPUT_CURRENT, it returns the current input mode.
//
// Default termbox input mode is TB_INPUT_ESC.
SO_IMPORT int tb_select_input_mode(int mode);
#define TB_OUTPUT_CURRENT 0
#define TB_OUTPUT_NORMAL 1
#define TB_OUTPUT_256 2
#define TB_OUTPUT_216 3
#define TB_OUTPUT_GRAYSCALE 4
#define TB_OUTPUT_TRUECOLOR 5
// Sets the termbox output mode. Termbox has three output options:
// 1. TB_OUTPUT_NORMAL => [1..8]
// This mode provides 8 different colors:
// black, red, green, yellow, blue, magenta, cyan, white
// Shortcut: TB_BLACK, TB_RED, ...
// Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE
//
// Example usage:
// tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
//
// 2. TB_OUTPUT_256 => [0..256]
// In this mode you can leverage the 256 terminal mode:
// 0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
// 0x08 - 0x0f: TB_* | TB_BOLD
// 0x10 - 0xe7: 216 different colors
// 0xe8 - 0xff: 24 different shades of grey
//
// Example usage:
// tb_change_cell(x, y, '@', 184, 240);
// tb_change_cell(x, y, '@', 0xb8, 0xf0);
//
// 3. TB_OUTPUT_216 => [0..216]
// This mode supports the 3rd range of the 256 mode only.
// But you don't need to provide an offset.
//
// 4. TB_OUTPUT_GRAYSCALE => [0..23]
// This mode supports the 4th range of the 256 mode only.
// But you dont need to provide an offset.
//
// 5. TB_OUTPUT_TRUECOLOR => [0x000000..0xFFFFFF]
// This mode supports 24-bit true color. Format is 0xRRGGBB.
//
// Execute build/src/demo/output to see its impact on your terminal.
//
// If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode.
//
// Default termbox output mode is TB_OUTPUT_NORMAL.
SO_IMPORT int tb_select_output_mode(int mode);
// Wait for an event up to 'timeout' milliseconds and fill the 'event'
// structure with it, when the event is available. Returns the type of the
// event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
// there were no event during 'timeout' period.
SO_IMPORT int tb_peek_event(struct tb_event* event, int timeout);
// Wait for an event forever and fill the 'event' structure with it, when the
// event is available. Returns the type of the event (one of TB_EVENT_
// constants) or -1 if there was an error.
SO_IMPORT int tb_poll_event(struct tb_event* event);
// Utility utf8 functions.
#define TB_EOF -1
SO_IMPORT int utf8_char_length(char c);
SO_IMPORT int utf8_char_to_unicode(uint32_t* out, const char* c);
SO_IMPORT int utf8_unicode_to_char(char* out, uint32_t c);
// c++
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -1,25 +0,0 @@
/* termfx.h
*
* provide simple terminal interface for lua
*
* Gunnar Zötl <gz@tset.de>, 2014-2015
* Released under the terms of the MIT license. See file LICENSE for details.
*/
#define _VERSION "0.7.1"
#define TFXCELL "TfxCell"
#define TFXBUFFER "TfxBuffer"
#define TOSTRING_BUFSIZ 64
#if LUA_VERSION_NUM == 501
#define luaL_newlib(L,funcs) lua_newtable(L); luaL_register(L, NULL, funcs)
#define luaL_setfuncs(L,funcs,x) luaL_register(L, NULL, funcs)
#define lua_rawlen(L, i) lua_objlen(L, i)
#endif
#define maxargs(L, n) if (lua_gettop(L) > (n)) { return luaL_error(L, "invalid number of arguments."); }
/* from termfx_color.c */
extern void tfx_color_init(lua_State *L);

@ -1,219 +0,0 @@
/* termfx_color.c
*
* provide simple terminal interface for lua
*
* Gunnar Zötl <gz@tset.de>, 2014-2015
* Released under the terms of the MIT license. See file LICENSE for details.
*/
#include "lua.h"
#include "lauxlib.h"
#include "termbox.h"
#include "termfx.h"
static const char* xterm_color_data[256] = {
"#000000", "#800000", "#008000", "#808000", "#000080", "#800080", "#008080", "#c0c0c0",
"#808080", "#ff0000", "#00ff00", "#ffff00", "#0000ff", "#ff00ff", "#00ffff", "#ffffff",
"#000000", "#00005f", "#000087", "#0000af", "#0000d7", "#0000ff",
"#005f00", "#005f5f", "#005f87", "#005faf", "#005fd7", "#005fff",
"#008700", "#00875f", "#008787", "#0087af", "#0087d7", "#0087ff",
"#00af00", "#00af5f", "#00af87", "#00afaf", "#00afd7", "#00afff",
"#00d700", "#00d75f", "#00d787", "#00d7af", "#00d7d7", "#00d7ff",
"#00ff00", "#00ff5f", "#00ff87", "#00ffaf", "#00ffd7", "#00ffff",
"#5f0000", "#5f005f", "#5f0087", "#5f00af", "#5f00d7", "#5f00ff",
"#5f5f00", "#5f5f5f", "#5f5f87", "#5f5faf", "#5f5fd7", "#5f5fff",
"#5f8700", "#5f875f", "#5f8787", "#5f87af", "#5f87d7", "#5f87ff",
"#5faf00", "#5faf5f", "#5faf87", "#5fafaf", "#5fafd7", "#5fafff",
"#5fd700", "#5fd75f", "#5fd787", "#5fd7af", "#5fd7d7", "#5fd7ff",
"#5fff00", "#5fff5f", "#5fff87", "#5fffaf", "#5fffd7", "#5fffff",
"#870000", "#87005f", "#870087", "#8700af", "#8700d7", "#8700ff",
"#875f00", "#875f5f", "#875f87", "#875faf", "#875fd7", "#875fff",
"#878700", "#87875f", "#878787", "#8787af", "#8787d7", "#8787ff",
"#87af00", "#87af5f", "#87af87", "#87afaf", "#87afd7", "#87afff",
"#87d700", "#87d75f", "#87d787", "#87d7af", "#87d7d7", "#87d7ff",
"#87ff00", "#87ff5f", "#87ff87", "#87ffaf", "#87ffd7", "#87ffff",
"#af0000", "#af005f", "#af0087", "#af00af", "#af00d7", "#af00ff",
"#af5f00", "#af5f5f", "#af5f87", "#af5faf", "#af5fd7", "#af5fff",
"#af8700", "#af875f", "#af8787", "#af87af", "#af87d7", "#af87ff",
"#afaf00", "#afaf5f", "#afaf87", "#afafaf", "#afafd7", "#afafff",
"#afd700", "#afd75f", "#afd787", "#afd7af", "#afd7d7", "#afd7ff",
"#afff00", "#afff5f", "#afff87", "#afffaf", "#afffd7", "#afffff",
"#d70000", "#d7005f", "#d70087", "#d700af", "#d700d7", "#d700ff",
"#d75f00", "#d75f5f", "#d75f87", "#d75faf", "#d75fd7", "#d75fff",
"#d78700", "#d7875f", "#d78787", "#d787af", "#d787d7", "#d787ff",
"#d7af00", "#d7af5f", "#d7af87", "#d7afaf", "#d7afd7", "#d7afff",
"#d7d700", "#d7d75f", "#d7d787", "#d7d7af", "#d7d7d7", "#d7d7ff",
"#d7ff00", "#d7ff5f", "#d7ff87", "#d7ffaf", "#d7ffd7", "#d7ffff",
"#ff0000", "#ff005f", "#ff0087", "#ff00af", "#ff00d7", "#ff00ff",
"#ff5f00", "#ff5f5f", "#ff5f87", "#ff5faf", "#ff5fd7", "#ff5fff",
"#ff8700", "#ff875f", "#ff8787", "#ff87af", "#ff87d7", "#ff87ff",
"#ffaf00", "#ffaf5f", "#ffaf87", "#ffafaf", "#ffafd7", "#ffafff",
"#ffd700", "#ffd75f", "#ffd787", "#ffd7af", "#ffd7d7", "#ffd7ff",
"#ffff00", "#ffff5f", "#ffff87", "#ffffaf", "#ffffd7", "#ffffff",
"#080808", "#121212", "#1c1c1c", "#262626", "#303030", "#3a3a3a",
"#444444", "#4e4e4e", "#585858", "#626262", "#6c6c6c", "#767676",
"#808080", "#8a8a8a", "#949494", "#9e9e9e", "#a8a8a8", "#b2b2b2",
"#bcbcbc", "#c6c6c6", "#d0d0d0", "#dadada", "#e4e4e4", "#eeeeee"
};
/* tfx_rgb2color
*
* maps r, g, b values in the range 0..5 to an xterm color number. Works
* only in COL216 and COL256 modes. As can be seen by the table above,
* the 216 colors are arranged such that the color for any rgb triplet
* can be found at 16 + (r * 6 + g) * 6 + b, for 0 <= r, g, b <= 5
*
* Arguments:
* L Lua State
*
* Lua Stack:
* 1 red value
* 2 green value
* 3 blue value
*
* Lua Returns:
* +1 the color number, or nil on error.
*/
static int tfx_rgb2color(lua_State *L)
{
maxargs(L, 3);
unsigned int r = luaL_checkinteger(L, 1);
unsigned int g = luaL_checkinteger(L, 2);
unsigned int b = luaL_checkinteger(L, 3);
if (r > 5 || g > 5 || b > 5) {
lua_pushnil(L);
return 1;
}
int omode = tb_select_output_mode(TB_OUTPUT_CURRENT);
if (omode == TB_OUTPUT_256 || omode == TB_OUTPUT_216) {
int col = (r * 6 + g) * 6 + b;
if (omode == TB_OUTPUT_256) col += 16;
lua_pushinteger(L, col);
} else {
lua_pushnil(L);
}
return 1;
}
/* tfx_rgb2color
*
* maps a grey value in the range 0..25 to an xterm color number. Works
* only in GREYSCALE and COL256 modes. The greys are in one consecutive
* block, starting from 232, except for #000000 and #ffffff, which are
* only available in COL256 mode.
*
* Arguments:
* L Lua State
*
* Lua Stack:
* 1 grey value
*
* Lua Returns:
* +1 the color number, or nil on error.
*/
static int tfx_grey2color(lua_State *L)
{
maxargs(L, 1);
unsigned int v = luaL_checkinteger(L, 1);
if (v > 25) {
lua_pushnil(L);
return 1;
}
int omode = tb_select_output_mode(TB_OUTPUT_CURRENT);
if (omode == TB_OUTPUT_256 || omode == TB_OUTPUT_GRAYSCALE) {
int col;
if (omode == TB_OUTPUT_GRAYSCALE) {
if (v < 1)
v = 1;
else if (v > 24)
v = 24;
}
if (v == 0)
col = 16;
else if (v == 25)
col = 231;
else
col = 231 + v;
if (omode == TB_OUTPUT_GRAYSCALE)
col -= 232;
lua_pushinteger(L, col);
} else {
lua_pushnil(L);
}
return 1;
}
/* tfx_colorinfo
*
* finds the color string from a xterm color number from the above table,
* and also returns its r, g, b values.
*
* Arguments:
* L Lua State
*
* Lua Stack:
* 1 color number
*
* Lua Returns:
* +1 color string "#XXXXXX", or nil on error.
* +2 r value or nothing
* +3 g value or nothing
* +4 b value or nothing
*/
static int tfx_colorinfo(lua_State *L)
{
int omode = tb_select_output_mode(TB_OUTPUT_CURRENT);
unsigned int col = luaL_checkinteger(L, 1);
if ((omode == TB_OUTPUT_NORMAL && col >= 16) || col > 255) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
maxargs(L, 1);
if (omode == TB_OUTPUT_NORMAL) {
if (col > 0 && col <= 8) {
col -= 1;
} else {
col = 8;
}
} else if (omode == TB_OUTPUT_216) {
col += 16;
} else if (omode == TB_OUTPUT_GRAYSCALE) {
col += 232;
}
if (col < 256) {
unsigned int r, g, b;
lua_pushstring(L, xterm_color_data[col]);
sscanf(xterm_color_data[col], "#%02x%02x%02x", &r, &g, &b);
lua_pushinteger(L, r);
lua_pushinteger(L, g);
lua_pushinteger(L, b);
return 4;
}
lua_pushnil(L);
return 1;
}
/* TermFX color handling function list
*/
static const struct luaL_Reg ltermfx_color [] ={
{"rgb2color", tfx_rgb2color},
{"grey2color", tfx_grey2color},
{"colorinfo", tfx_colorinfo},
{NULL, NULL}
};
/* export color functions into termfx function table
*/
void tfx_color_init(lua_State *L)
{
luaL_setfuncs(L, ltermfx_color, 0);
}

@ -1,15 +0,0 @@
*.o
*.so
*.so.*
*.obj
*.lib
*.dll*
*.user
*.sdf
Debug
Release
*.manifest
*.swp
*.suo
x64

@ -1,11 +0,0 @@
This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
and Linux.
Please use the project page at GitHub
https://github.com/diegonehab/luasocket
to file bug reports or propose changes.
Have fun,
Diego Nehab.

@ -1 +0,0 @@
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/$USER/build/macosx/include LUAPREFIX_macosx=/Users/$USER/build/macosx install-both

@ -1,49 +0,0 @@
# luasocket makefile
#
# see src/makefile for description of how to customize the build
#
# Targets:
# install install system independent support
# install-unix also install unix-only support
# install-both install for lua51 lua52 lua53
# install-both-unix also install unix-only
# print print the build settings
PLAT?= linux
PLATS= macosx linux win32 win64 mingw freebsd solaris
all: $(PLAT)
$(PLATS) none install install-unix local clean:
$(MAKE) -C src $@
print:
$(MAKE) -C src $@
test:
lua test/hello.lua
install-both:
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install LUAV=5.1
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.2
@cd src; $(MAKE) install LUAV=5.2
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.3
@cd src; $(MAKE) install LUAV=5.3
install-both-unix:
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.1
@cd src; $(MAKE) install-unix LUAV=5.1
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.2
@cd src; $(MAKE) install-unix LUAV=5.2
$(MAKE) clean
@cd src; $(MAKE) $(PLAT) LUAV=5.3
@cd src; $(MAKE) install-unix LUAV=5.3
.PHONY: test

@ -1,139 +0,0 @@
#--------------------------------------------------------------------------
# Distribution makefile
#--------------------------------------------------------------------------
DIST = luasocket-3.0-rc1
TEST = \
test/README \
test/hello.lua \
test/testclnt.lua \
test/testsrvr.lua \
test/testsupport.lua
SAMPLES = \
samples/README \
samples/cddb.lua \
samples/daytimeclnt.lua \
samples/echoclnt.lua \
samples/echosrvr.lua \
samples/mclisten.lua \
samples/mcsend.lua \
samples/listener.lua \
samples/lpr.lua \
samples/talker.lua \
samples/tinyirc.lua
ETC = \
etc/README \
etc/b64.lua \
etc/check-links.lua \
etc/check-memory.lua \
etc/dict.lua \
etc/dispatch.lua \
etc/eol.lua \
etc/forward.lua \
etc/get.lua \
etc/lp.lua \
etc/qp.lua \
etc/tftp.lua
SRC = \
src/makefile \
src/auxiliar.c \
src/auxiliar.h \
src/buffer.c \
src/buffer.h \
src/except.c \
src/except.h \
src/inet.c \
src/inet.h \
src/io.c \
src/io.h \
src/luasocket.c \
src/luasocket.h \
src/mime.c \
src/mime.h \
src/options.c \
src/options.h \
src/select.c \
src/select.h \
src/socket.h \
src/tcp.c \
src/tcp.h \
src/timeout.c \
src/timeout.h \
src/udp.c \
src/udp.h \
src/unix.c \
src/serial.c \
src/unix.h \
src/usocket.c \
src/usocket.h \
src/wsocket.c \
src/wsocket.h \
src/ftp.lua \
src/http.lua \
src/ltn12.lua \
src/mime.lua \
src/smtp.lua \
src/socket.lua \
src/headers.lua \
src/tp.lua \
src/url.lua
MAKE = \
makefile \
luasocket.sln \
luasocket-scm-0.rockspec \
Lua51.props \
Lua52.props \
socket.vcxproj.filters \
mime.vcxproj.filters \
socket.vcxproj \
mime.vcxproj
DOC = \
doc/dns.html \
doc/ftp.html \
doc/index.html \
doc/http.html \
doc/installation.html \
doc/introduction.html \
doc/ltn12.html \
doc/luasocket.png \
doc/mime.html \
doc/reference.css \
doc/reference.html \
doc/smtp.html \
doc/socket.html \
doc/tcp.html \
doc/udp.html \
doc/url.html
dist:
mkdir -p $(DIST)
cp -vf NEW $(DIST)
cp -vf LICENSE $(DIST)
cp -vf README $(DIST)
cp -vf $(MAKE) $(DIST)
mkdir -p $(DIST)/etc
cp -vf $(ETC) $(DIST)/etc
mkdir -p $(DIST)/src
cp -vf $(SRC) $(DIST)/src
mkdir -p $(DIST)/doc
cp -vf $(DOC) $(DIST)/doc
mkdir -p $(DIST)/samples
cp -vf $(SAMPLES) $(DIST)/samples
mkdir -p $(DIST)/test
cp -vf $(TEST) $(DIST)/test
tar -zcvf $(DIST).tar.gz $(DIST)
zip -r $(DIST).zip $(DIST)
clean:
\rm -rf $(DIST) $(DIST).tar.gz $(DIST).zip

@ -1,154 +0,0 @@
/*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include <string.h>
#include <stdio.h>
/*-------------------------------------------------------------------------*\
* Initializes the module
\*-------------------------------------------------------------------------*/
int auxiliar_open(lua_State *L) {
(void) L;
return 0;
}
/*-------------------------------------------------------------------------*\
* Creates a new class with given methods
* Methods whose names start with __ are passed directly to the metatable.
\*-------------------------------------------------------------------------*/
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
luaL_newmetatable(L, classname); /* mt */
/* create __index table to place methods */
lua_pushstring(L, "__index"); /* mt,"__index" */
lua_newtable(L); /* mt,"__index",it */
/* put class name into class metatable */
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
lua_rawset(L, -3); /* mt,"__index",it */
/* pass all methods that start with _ to the metatable, and all others
* to the index table */
for (; func->name; func++) { /* mt,"__index",it */
lua_pushstring(L, func->name);
lua_pushcfunction(L, func->func);
lua_rawset(L, func->name[0] == '_' ? -5: -3);
}
lua_rawset(L, -3); /* mt */
lua_pop(L, 1);
}
/*-------------------------------------------------------------------------*\
* Prints the value of a class in a nice way
\*-------------------------------------------------------------------------*/
int auxiliar_tostring(lua_State *L) {
char buf[32];
if (!lua_getmetatable(L, 1)) goto error;
lua_pushstring(L, "__index");
lua_gettable(L, -2);
if (!lua_istable(L, -1)) goto error;
lua_pushstring(L, "class");
lua_gettable(L, -2);
if (!lua_isstring(L, -1)) goto error;
sprintf(buf, "%p", lua_touserdata(L, 1));
lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf);
return 1;
error:
lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'");
lua_error(L);
return 1;
}
/*-------------------------------------------------------------------------*\
* Insert class into group
\*-------------------------------------------------------------------------*/
void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) {
luaL_getmetatable(L, classname);
lua_pushstring(L, groupname);
lua_pushboolean(L, 1);
lua_rawset(L, -3);
lua_pop(L, 1);
}
/*-------------------------------------------------------------------------*\
* Make sure argument is a boolean
\*-------------------------------------------------------------------------*/
int auxiliar_checkboolean(lua_State *L, int objidx) {
if (!lua_isboolean(L, objidx))
auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
return lua_toboolean(L, objidx);
}
/*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given class, abort with
* error otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
void *data = auxiliar_getclassudata(L, classname, objidx);
if (!data) {
char msg[45];
sprintf(msg, "%.35s expected", classname);
luaL_argerror(L, objidx, msg);
}
return data;
}
/*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given group, abort with
* error otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
void *data = auxiliar_getgroupudata(L, groupname, objidx);
if (!data) {
char msg[45];
sprintf(msg, "%.35s expected", groupname);
luaL_argerror(L, objidx, msg);
}
return data;
}
/*-------------------------------------------------------------------------*\
* Set object class
\*-------------------------------------------------------------------------*/
void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
luaL_getmetatable(L, classname);
if (objidx < 0) objidx--;
lua_setmetatable(L, objidx);
}
/*-------------------------------------------------------------------------*\
* Get a userdata pointer if object belongs to a given group. Return NULL
* otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
if (!lua_getmetatable(L, objidx))
return NULL;
lua_pushstring(L, groupname);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
return NULL;
} else {
lua_pop(L, 2);
return lua_touserdata(L, objidx);
}
}
/*-------------------------------------------------------------------------*\
* Get a userdata pointer if object belongs to a given class. Return NULL
* otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
return luaL_testudata(L, objidx, classname);
}
/*-------------------------------------------------------------------------*\
* Throws error when argument does not have correct type.
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
\*-------------------------------------------------------------------------*/
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
}

@ -1,54 +0,0 @@
#ifndef AUXILIAR_H
#define AUXILIAR_H
/*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
*
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
* group is a name associated with a class. A class can belong to any number
* of groups. This module provides the functionality to:
*
* - create new classes
* - add classes to groups
* - set the class of objects
* - check if an object belongs to a given class or group
* - get the userdata associated to objects
* - print objects in a pretty way
*
* LuaSocket class names follow the convention <module>{<class>}. Modules
* can define any number of classes and groups. The module tcp.c, for
* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
* the groups tcp{client,server} and tcp{any}. Module functions can then
* perform type-checking on their arguments by either class or group.
*
* LuaSocket metatables define the __index metamethod as being a table. This
* table has one field for each method supported by the class, and a field
* "class" with the class name.
*
* The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib.
\*=========================================================================*/
#include "luasocket.h"
#ifndef _WIN32
#pragma GCC visibility push(hidden)
#endif
int auxiliar_open(lua_State *L);
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
int auxiliar_tostring(lua_State *L);
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
int auxiliar_checkboolean(lua_State *L, int objidx);
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
#ifndef _WIN32
#pragma GCC visibility pop
#endif
#endif /* AUXILIAR_H */

@ -1,270 +0,0 @@
/*=========================================================================*\
* Input/Output interface for Lua programs
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"
#include "buffer.h"
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b);
static int recvline(p_buffer buf, luaL_Buffer *b);
static int recvall(p_buffer buf, luaL_Buffer *b);
static int buffer_get(p_buffer buf, const char **data, size_t *count);
static void buffer_skip(p_buffer buf, size_t count);
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
#endif
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int buffer_open(lua_State *L) {
(void) L;
return 0;
}
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
buf->first = buf->last = 0;
buf->io = io;
buf->tm = tm;
buf->received = buf->sent = 0;
buf->birthday = timeout_gettime();
}
/*-------------------------------------------------------------------------*\
* object:getstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
lua_pushnumber(L, (lua_Number) buf->received);
lua_pushnumber(L, (lua_Number) buf->sent);
lua_pushnumber(L, timeout_gettime() - buf->birthday);
return 3;
}
/*-------------------------------------------------------------------------*\
* object:setstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* object:send() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_send(lua_State *L, p_buffer buf) {
int top = lua_gettop(L);
int err = IO_DONE;
size_t size = 0, sent = 0;
const char *data = luaL_checklstring(L, 2, &size);
long start = (long) luaL_optnumber(L, 3, 1);
long end = (long) luaL_optnumber(L, 4, -1);
timeout_markstart(buf->tm);
if (start < 0) start = (long) (size+start+1);
if (end < 0) end = (long) (size+end+1);
if (start < 1) start = (long) 1;
if (end > (long) size) end = (long) size;
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
/* check if there was an error */
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, (lua_Number) (sent+start-1));
} else {
lua_pushnumber(L, (lua_Number) (sent+start-1));
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
#endif
return lua_gettop(L) - top;
}
/*-------------------------------------------------------------------------*\
* object:receive() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_receive(lua_State *L, p_buffer buf) {
int err = IO_DONE, top = lua_gettop(L);
luaL_Buffer b;
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
timeout_markstart(buf->tm);
/* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */
luaL_buffinit(L, &b);
luaL_addlstring(&b, part, size);
/* receive new patterns */
if (!lua_isnumber(L, 2)) {
const char *p= luaL_optstring(L, 2, "*l");
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
/* get a fixed number of bytes (minus what was already partially
* received) */
} else {
double n = lua_tonumber(L, 2);
size_t wanted = (size_t) n;
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
if (size == 0 || wanted > size)
err = recvraw(buf, wanted-size, &b);
}
/* check if there was an error */
if (err != IO_DONE) {
/* we can't push anyting in the stack before pushing the
* contents of the buffer. this is the reason for the complication */
luaL_pushresult(&b);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushvalue(L, -2);
lua_pushnil(L);
lua_replace(L, -4);
} else {
luaL_pushresult(&b);
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
#endif
return lua_gettop(L) - top;
}
/*-------------------------------------------------------------------------*\
* Determines if there is any data in the read buffer
\*-------------------------------------------------------------------------*/
int buffer_isempty(p_buffer buf) {
return buf->first >= buf->last;
}
/*=========================================================================*\
* Internal functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Sends a block of data (unbuffered)
\*-------------------------------------------------------------------------*/
#define STEPSIZE 8192
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
p_io io = buf->io;
p_timeout tm = buf->tm;
size_t total = 0;
int err = IO_DONE;
while (total < count && err == IO_DONE) {
size_t done = 0;
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
err = io->send(io->ctx, data+total, step, &done, tm);
total += done;
}
*sent = total;
buf->sent += total;
return err;
}
/*-------------------------------------------------------------------------*\
* Reads a fixed number of bytes (buffered)
\*-------------------------------------------------------------------------*/
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) {
int err = IO_DONE;
size_t total = 0;
while (err == IO_DONE) {
size_t count; const char *data;
err = buffer_get(buf, &data, &count);
count = MIN(count, wanted - total);
luaL_addlstring(b, data, count);
buffer_skip(buf, count);
total += count;
if (total >= wanted) break;
}
return err;
}
/*-------------------------------------------------------------------------*\
* Reads everything until the connection is closed (buffered)
\*-------------------------------------------------------------------------*/
static int recvall(p_buffer buf, luaL_Buffer *b) {
int err = IO_DONE;
size_t total = 0;
while (err == IO_DONE) {
const char *data; size_t count;
err = buffer_get(buf, &data, &count);
total += count;
luaL_addlstring(b, data, count);
buffer_skip(buf, count);
}
if (err == IO_CLOSED) {
if (total > 0) return IO_DONE;
else return IO_CLOSED;
} else return err;
}
/*-------------------------------------------------------------------------*\
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
* are not returned by the function and are discarded from the buffer
\*-------------------------------------------------------------------------*/
static int recvline(p_buffer buf, luaL_Buffer *b) {
int err = IO_DONE;
while (err == IO_DONE) {
size_t count, pos; const char *data;
err = buffer_get(buf, &data, &count);
pos = 0;
while (pos < count && data[pos] != '\n') {
/* we ignore all \r's */
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
pos++;
}
if (pos < count) { /* found '\n' */
buffer_skip(buf, pos+1); /* skip '\n' too */
break; /* we are done */
} else /* reached the end of the buffer */
buffer_skip(buf, pos);
}
return err;
}
/*-------------------------------------------------------------------------*\
* Skips a given number of bytes from read buffer. No data is read from the
* transport layer
\*-------------------------------------------------------------------------*/
static void buffer_skip(p_buffer buf, size_t count) {
buf->received += count;
buf->first += count;
if (buffer_isempty(buf))
buf->first = buf->last = 0;
}
/*-------------------------------------------------------------------------*\
* Return any data available in buffer, or get more data from transport layer
* if buffer is empty
\*-------------------------------------------------------------------------*/
static int buffer_get(p_buffer buf, const char **data, size_t *count) {
int err = IO_DONE;
p_io io = buf->io;
p_timeout tm = buf->tm;
if (buffer_isempty(buf)) {
size_t got;
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
buf->first = 0;
buf->last = got;
}
*count = buf->last - buf->first;
*data = buf->data + buf->first;
return err;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save