Compare commits
No commits in common. 'develop' and 'master' have entirely different histories.
@ -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
|
||||
|
||||
@ -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,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, ¢er->v1);
|
||||
ccd->center2(obj2, ¢er->v2);
|
||||
ccdVec3Sub2(¢er->v, ¢er->v1, ¢er->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,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,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…
Reference in New Issue